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 (MustPrune(this)) {
254 GetChildCount(&numChildren
);
255 *pcountChildren
= numChildren
;
256 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
261 STDMETHODIMP
nsAccessibleWrap::get_accChild(
262 /* [in] */ VARIANT varChild
,
263 /* [retval][out] */ IDispatch __RPC_FAR
*__RPC_FAR
*ppdispChild
)
267 if (!mWeakShell
|| varChild
.vt
!= VT_I4
)
270 if (varChild
.lVal
== CHILDID_SELF
) {
271 *ppdispChild
= static_cast<IDispatch
*>(this);
276 nsCOMPtr
<nsIAccessible
> childAccessible
;
277 if (!MustPrune(this)) {
278 GetChildAt(varChild
.lVal
- 1, getter_AddRefs(childAccessible
));
279 if (childAccessible
) {
280 *ppdispChild
= NativeAccessible(childAccessible
);
283 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
285 return (*ppdispChild
)? S_OK
: E_FAIL
;
288 STDMETHODIMP
nsAccessibleWrap::get_accName(
289 /* [optional][in] */ VARIANT varChild
,
290 /* [retval][out] */ BSTR __RPC_FAR
*pszName
)
294 nsCOMPtr
<nsIAccessible
> xpAccessible
;
295 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
299 nsresult rv
= xpAccessible
->GetName(name
);
301 return GetHRESULT(rv
);
304 // Valid return value for the name:
305 // The name was not provided, e.g. no alt attribute for an image.
306 // A screen reader may choose to invent its own accessible name, e.g. from
307 // an image src attribute.
308 // See nsHTMLImageAccessible::GetName()
312 *pszName
= ::SysAllocStringLen(name
.get(), name
.Length());
314 return E_OUTOFMEMORY
;
317 NS_ASSERTION(mIsInitialized
, "Access node was not initialized");
319 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
325 STDMETHODIMP
nsAccessibleWrap::get_accValue(
326 /* [optional][in] */ VARIANT varChild
,
327 /* [retval][out] */ BSTR __RPC_FAR
*pszValue
)
331 nsCOMPtr
<nsIAccessible
> xpAccessible
;
332 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
335 if (NS_FAILED(xpAccessible
->GetValue(value
)))
338 // see bug 438784: Need to expose URL on doc's value attribute.
339 // For this, reverting part of fix for bug 425693 to make this MSAA method
340 // behave IAccessible2-style.
344 *pszValue
= ::SysAllocStringLen(value
.get(), value
.Length());
346 return E_OUTOFMEMORY
;
348 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
353 nsAccessibleWrap::get_accDescription(VARIANT varChild
,
354 BSTR __RPC_FAR
*pszDescription
)
357 *pszDescription
= NULL
;
359 nsCOMPtr
<nsIAccessible
> xpAccessible
;
360 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
364 // For items that are a choice in a list of choices, use MSAA description
365 // field to shoehorn positional info, it's becoming a defacto standard use for
368 nsAutoString description
;
370 // Try to get group attributes to make a positional description string. We
371 // can't use nsIAccessible::groupPosition because the method isn't supposed
372 // to work with elements exposing 'level' attribute only (like HTML headings).
373 nsCOMPtr
<nsIPersistentProperties
> attributes
;
374 nsresult rv
= xpAccessible
->GetAttributes(getter_AddRefs(attributes
));
375 NS_ENSURE_SUCCESS(rv
, rv
);
377 return NS_ERROR_FAILURE
;
379 PRInt32 groupLevel
= 0;
380 PRInt32 itemsInGroup
= 0;
381 PRInt32 positionInGroup
= 0;
382 nsAccUtils::GetAccGroupAttrs(attributes
, &groupLevel
, &positionInGroup
,
385 if (positionInGroup
> 0) {
386 if (groupLevel
> 0) {
387 // XXX: How do we calculate the number of children? Now we append
388 // " with [numChildren]c" for tree item. In the future we may need to
389 // use the ARIA owns property to calculate that if it's present.
390 PRInt32 numChildren
= 0;
392 PRUint32 currentRole
= 0;
393 rv
= xpAccessible
->GetFinalRole(¤tRole
);
394 if (NS_SUCCEEDED(rv
) &&
395 currentRole
== nsIAccessibleRole::ROLE_OUTLINEITEM
) {
396 nsCOMPtr
<nsIAccessible
> child
;
397 xpAccessible
->GetFirstChild(getter_AddRefs(child
));
399 child
->GetFinalRole(¤tRole
);
400 if (currentRole
== nsIAccessibleRole::ROLE_GROUPING
) {
401 nsCOMPtr
<nsIAccessible
> groupChild
;
402 child
->GetFirstChild(getter_AddRefs(groupChild
));
404 groupChild
->GetFinalRole(¤tRole
);
406 (currentRole
== nsIAccessibleRole::ROLE_OUTLINEITEM
);
407 nsCOMPtr
<nsIAccessible
> nextGroupChild
;
408 groupChild
->GetNextSibling(getter_AddRefs(nextGroupChild
));
409 groupChild
.swap(nextGroupChild
);
413 nsCOMPtr
<nsIAccessible
> nextChild
;
414 child
->GetNextSibling(getter_AddRefs(nextChild
));
415 child
.swap(nextChild
);
420 nsTextFormatter::ssprintf(description
,
421 NS_LITERAL_STRING("L%d, %d of %d with %d").get(),
422 groupLevel
, positionInGroup
, itemsInGroup
,
425 nsTextFormatter::ssprintf(description
,
426 NS_LITERAL_STRING("L%d, %d of %d").get(),
427 groupLevel
, positionInGroup
, itemsInGroup
);
429 } else { // Position has no level
430 nsTextFormatter::ssprintf(description
,
431 NS_LITERAL_STRING("%d of %d").get(),
432 positionInGroup
, itemsInGroup
);
434 } else if (groupLevel
> 0) {
435 nsTextFormatter::ssprintf(description
, NS_LITERAL_STRING("L%d").get(),
439 if (!description
.IsEmpty()) {
440 *pszDescription
= ::SysAllocStringLen(description
.get(),
441 description
.Length());
442 return *pszDescription
? S_OK
: E_OUTOFMEMORY
;
445 xpAccessible
->GetDescription(description
);
446 if (!description
.IsEmpty()) {
447 // Signal to screen readers that this description is speakable
448 // and is not a formatted positional information description
449 // Don't localize the "Description: " part of this string, it will be
450 // parsed out by assistive technologies.
451 description
= NS_LITERAL_STRING("Description: ") + description
;
454 *pszDescription
= ::SysAllocStringLen(description
.get(),
455 description
.Length());
456 return *pszDescription
? S_OK
: E_OUTOFMEMORY
;
458 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
462 STDMETHODIMP
nsAccessibleWrap::get_accRole(
463 /* [optional][in] */ VARIANT varChild
,
464 /* [retval][out] */ VARIANT __RPC_FAR
*pvarRole
)
467 VariantInit(pvarRole
);
469 nsCOMPtr
<nsIAccessible
> xpAccessible
;
470 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
476 NS_ASSERTION(nsAccessible::IsTextInterfaceSupportCorrect(xpAccessible
), "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 (parent
&& Role(parent
) == nsIAccessibleRole::ROLE_TREE_TABLE
) {
493 msaaRole
= ROLE_SYSTEM_OUTLINEITEM
;
497 // -- Try enumerated role
498 if (msaaRole
!= USE_ROLE_STRING
) {
499 pvarRole
->vt
= VT_I4
;
500 pvarRole
->lVal
= msaaRole
; // Normal enumerated role
505 // Could not map to known enumerated MSAA role like ROLE_BUTTON
506 // Use BSTR role to expose role attribute or tag name + namespace
507 nsCOMPtr
<nsIDOMNode
> domNode
;
508 nsCOMPtr
<nsIAccessNode
> accessNode(do_QueryInterface(xpAccessible
));
512 accessNode
->GetDOMNode(getter_AddRefs(domNode
));
513 nsIContent
*content
= GetRoleContent(domNode
);
517 if (content
->IsNodeOfType(nsINode::eELEMENT
)) {
518 nsAutoString roleString
;
519 if (msaaRole
!= ROLE_SYSTEM_CLIENT
&&
520 !content
->GetAttr(kNameSpaceID_None
, nsAccessibilityAtoms::role
, roleString
)) {
521 nsINodeInfo
*nodeInfo
= content
->NodeInfo();
522 nodeInfo
->GetName(roleString
);
523 nsAutoString nameSpaceURI
;
524 nodeInfo
->GetNamespaceURI(nameSpaceURI
);
525 if (!nameSpaceURI
.IsEmpty()) {
526 // Only append name space if different from that of current document
527 roleString
+= NS_LITERAL_STRING(", ") + nameSpaceURI
;
530 if (!roleString
.IsEmpty()) {
531 pvarRole
->vt
= VT_BSTR
;
532 pvarRole
->bstrVal
= ::SysAllocString(roleString
.get());
536 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
540 STDMETHODIMP
nsAccessibleWrap::get_accState(
541 /* [optional][in] */ VARIANT varChild
,
542 /* [retval][out] */ VARIANT __RPC_FAR
*pvarState
)
545 VariantInit(pvarState
);
546 pvarState
->vt
= VT_I4
;
549 nsCOMPtr
<nsIAccessible
> xpAccessible
;
550 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
555 if (NS_FAILED(xpAccessible
->GetFinalState(&state
, nsnull
)))
558 pvarState
->lVal
= state
;
559 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
564 STDMETHODIMP
nsAccessibleWrap::get_accHelp(
565 /* [optional][in] */ VARIANT varChild
,
566 /* [retval][out] */ BSTR __RPC_FAR
*pszHelp
)
572 STDMETHODIMP
nsAccessibleWrap::get_accHelpTopic(
573 /* [out] */ BSTR __RPC_FAR
*pszHelpFile
,
574 /* [optional][in] */ VARIANT varChild
,
575 /* [retval][out] */ long __RPC_FAR
*pidTopic
)
582 STDMETHODIMP
nsAccessibleWrap::get_accKeyboardShortcut(
583 /* [optional][in] */ VARIANT varChild
,
584 /* [retval][out] */ BSTR __RPC_FAR
*pszKeyboardShortcut
)
587 *pszKeyboardShortcut
= NULL
;
588 nsCOMPtr
<nsIAccessible
> xpAccessible
;
589 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
591 nsAutoString shortcut
;
592 nsresult rv
= xpAccessible
->GetKeyboardShortcut(shortcut
);
596 *pszKeyboardShortcut
= ::SysAllocStringLen(shortcut
.get(),
598 return *pszKeyboardShortcut
? S_OK
: E_OUTOFMEMORY
;
600 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
604 STDMETHODIMP
nsAccessibleWrap::get_accFocus(
605 /* [retval][out] */ VARIANT __RPC_FAR
*pvarChild
)
607 // VT_EMPTY: None. This object does not have the keyboard focus itself
608 // and does not contain a child that has the keyboard focus.
609 // VT_I4: lVal is CHILDID_SELF. The object itself has the keyboard focus.
610 // VT_I4: lVal contains the child ID of the child element with the keyboard focus.
611 // VT_DISPATCH: pdispVal member is the address of the IDispatch interface
612 // for the child object with the keyboard focus.
615 return E_FAIL
; // This node is shut down
618 VariantInit(pvarChild
);
620 // Return the current IAccessible child that has focus
621 nsCOMPtr
<nsIAccessible
> focusedAccessible
;
622 GetFocusedChild(getter_AddRefs(focusedAccessible
));
623 if (focusedAccessible
== this) {
624 pvarChild
->vt
= VT_I4
;
625 pvarChild
->lVal
= CHILDID_SELF
;
627 else if (focusedAccessible
) {
628 pvarChild
->vt
= VT_DISPATCH
;
629 pvarChild
->pdispVal
= NativeAccessible(focusedAccessible
);
632 pvarChild
->vt
= VT_EMPTY
; // No focus or focus is not a child
635 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
639 // This helper class implements IEnumVARIANT for a nsIArray containing nsIAccessible objects.
641 class AccessibleEnumerator
: public IEnumVARIANT
644 AccessibleEnumerator(nsIArray
* aArray
) : mArray(aArray
), mCurIndex(0) { }
645 AccessibleEnumerator(const AccessibleEnumerator
& toCopy
) :
646 mArray(toCopy
.mArray
), mCurIndex(toCopy
.mCurIndex
) { }
647 ~AccessibleEnumerator() { }
650 STDMETHODIMP
QueryInterface(REFIID iid
, void ** ppvObject
);
651 STDMETHODIMP_(ULONG
) AddRef(void);
652 STDMETHODIMP_(ULONG
) Release(void);
655 STDMETHODIMP
Next(unsigned long celt
, VARIANT FAR
* rgvar
, unsigned long FAR
* pceltFetched
);
656 STDMETHODIMP
Skip(unsigned long celt
);
662 STDMETHODIMP
Clone(IEnumVARIANT FAR
* FAR
* ppenum
);
665 nsCOMPtr
<nsIArray
> mArray
;
667 nsAutoRefCnt mRefCnt
;
671 AccessibleEnumerator::QueryInterface(REFIID iid
, void ** ppvObject
)
674 if (iid
== IID_IEnumVARIANT
) {
675 *ppvObject
= static_cast<IEnumVARIANT
*>(this);
679 if (iid
== IID_IUnknown
) {
680 *ppvObject
= static_cast<IUnknown
*>(this);
686 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
687 return E_NOINTERFACE
;
691 AccessibleEnumerator::AddRef(void)
697 AccessibleEnumerator::Release(void)
706 AccessibleEnumerator::Next(unsigned long celt
, VARIANT FAR
* rgvar
, unsigned long FAR
* pceltFetched
)
710 mArray
->GetLength(&length
);
714 // Can't get more elements than there are...
715 if (celt
> length
- mCurIndex
) {
717 celt
= length
- mCurIndex
;
720 for (PRUint32 i
= 0; i
< celt
; ++i
, ++mCurIndex
) {
721 // Copy the elements of the array into rgvar
722 nsCOMPtr
<nsIAccessible
> accel(do_QueryElementAt(mArray
, mCurIndex
));
723 NS_ASSERTION(accel
, "Invalid pointer in mArray");
726 rgvar
[i
].vt
= VT_DISPATCH
;
727 rgvar
[i
].pdispVal
= nsAccessibleWrap::NativeAccessible(accel
);
732 *pceltFetched
= celt
;
735 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
741 AccessibleEnumerator::Clone(IEnumVARIANT FAR
* FAR
* ppenum
)
744 *ppenum
= new AccessibleEnumerator(*this);
746 return E_OUTOFMEMORY
;
748 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
753 AccessibleEnumerator::Skip(unsigned long celt
)
757 mArray
->GetLength(&length
);
758 // Check if we can skip the requested number of elements
759 if (celt
> length
- mCurIndex
) {
764 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
769 * This method is called when a client wants to know which children of a node
770 * are selected. Note that this method can only find selected children for
771 * nsIAccessible object which implement nsIAccessibleSelectable.
773 * The VARIANT return value arguement is expected to either contain a single IAccessible
774 * or an IEnumVARIANT of IAccessibles. We return the IEnumVARIANT regardless of the number
775 * of children selected, unless there are none selected in which case we return an empty
778 * We get the selected options from the select's accessible object and wrap
779 * those in an AccessibleEnumerator which we then put in the return VARIANT.
781 * returns a VT_EMPTY VARIANT if:
782 * - there are no selected children for this object
783 * - the object is not the type that can have children selected
785 STDMETHODIMP
nsAccessibleWrap::get_accSelection(VARIANT __RPC_FAR
*pvarChildren
)
788 VariantInit(pvarChildren
);
789 pvarChildren
->vt
= VT_EMPTY
;
791 nsCOMPtr
<nsIAccessibleSelectable
>
792 select(do_QueryInterface(static_cast<nsIAccessible
*>(this)));
794 if (select
) { // do we have an nsIAccessibleSelectable?
795 // we have an accessible that can have children selected
796 nsCOMPtr
<nsIArray
> selectedOptions
;
797 // gets the selected options as nsIAccessibles.
798 select
->GetSelectedChildren(getter_AddRefs(selectedOptions
));
799 if (selectedOptions
) { // false if the select has no children or none are selected
800 // 1) Create and initialize the enumeration
801 nsRefPtr
<AccessibleEnumerator
> pEnum
= new AccessibleEnumerator(selectedOptions
);
803 // 2) Put the enumerator in the VARIANT
805 return E_OUTOFMEMORY
;
806 pvarChildren
->vt
= VT_UNKNOWN
; // this must be VT_UNKNOWN for an IEnumVARIANT
807 NS_ADDREF(pvarChildren
->punkVal
= pEnum
);
810 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
814 STDMETHODIMP
nsAccessibleWrap::get_accDefaultAction(
815 /* [optional][in] */ VARIANT varChild
,
816 /* [retval][out] */ BSTR __RPC_FAR
*pszDefaultAction
)
819 *pszDefaultAction
= NULL
;
820 nsCOMPtr
<nsIAccessible
> xpAccessible
;
821 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
823 nsAutoString defaultAction
;
824 if (NS_FAILED(xpAccessible
->GetActionName(0, defaultAction
)))
827 *pszDefaultAction
= ::SysAllocStringLen(defaultAction
.get(),
828 defaultAction
.Length());
829 return *pszDefaultAction
? S_OK
: E_OUTOFMEMORY
;
832 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
836 STDMETHODIMP
nsAccessibleWrap::accSelect(
837 /* [in] */ long flagsSelect
,
838 /* [optional][in] */ VARIANT varChild
)
841 // currently only handle focus and selection
842 nsCOMPtr
<nsIAccessible
> xpAccessible
;
843 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
844 NS_ENSURE_TRUE(xpAccessible
, E_FAIL
);
846 if (flagsSelect
& (SELFLAG_TAKEFOCUS
|SELFLAG_TAKESELECTION
|SELFLAG_REMOVESELECTION
))
848 if (flagsSelect
& SELFLAG_TAKEFOCUS
)
849 xpAccessible
->TakeFocus();
851 if (flagsSelect
& SELFLAG_TAKESELECTION
)
852 xpAccessible
->TakeSelection();
854 if (flagsSelect
& SELFLAG_ADDSELECTION
)
855 xpAccessible
->SetSelected(PR_TRUE
);
857 if (flagsSelect
& SELFLAG_REMOVESELECTION
)
858 xpAccessible
->SetSelected(PR_FALSE
);
860 if (flagsSelect
& SELFLAG_EXTENDSELECTION
)
861 xpAccessible
->ExtendSelection();
866 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
870 STDMETHODIMP
nsAccessibleWrap::accLocation(
871 /* [out] */ long __RPC_FAR
*pxLeft
,
872 /* [out] */ long __RPC_FAR
*pyTop
,
873 /* [out] */ long __RPC_FAR
*pcxWidth
,
874 /* [out] */ long __RPC_FAR
*pcyHeight
,
875 /* [optional][in] */ VARIANT varChild
)
878 nsCOMPtr
<nsIAccessible
> xpAccessible
;
879 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
882 PRInt32 x
, y
, width
, height
;
883 if (NS_FAILED(xpAccessible
->GetBounds(&x
, &y
, &width
, &height
)))
892 } __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
897 STDMETHODIMP
nsAccessibleWrap::accNavigate(
898 /* [in] */ long navDir
,
899 /* [optional][in] */ VARIANT varStart
,
900 /* [retval][out] */ VARIANT __RPC_FAR
*pvarEndUpAt
)
903 nsCOMPtr
<nsIAccessible
> xpAccessibleStart
, xpAccessibleResult
;
904 GetXPAccessibleFor(varStart
, getter_AddRefs(xpAccessibleStart
));
905 if (!xpAccessibleStart
)
908 VariantInit(pvarEndUpAt
);
909 PRUint32 xpRelation
= 0;
913 xpAccessibleStart
->GetAccessibleBelow(getter_AddRefs(xpAccessibleResult
));
915 case NAVDIR_FIRSTCHILD
:
916 if (!MustPrune(xpAccessibleStart
)) {
917 xpAccessibleStart
->GetFirstChild(getter_AddRefs(xpAccessibleResult
));
920 case NAVDIR_LASTCHILD
:
921 if (!MustPrune(xpAccessibleStart
)) {
922 xpAccessibleStart
->GetLastChild(getter_AddRefs(xpAccessibleResult
));
926 xpAccessibleStart
->GetAccessibleToLeft(getter_AddRefs(xpAccessibleResult
));
929 xpAccessibleStart
->GetNextSibling(getter_AddRefs(xpAccessibleResult
));
931 case NAVDIR_PREVIOUS
:
932 xpAccessibleStart
->GetPreviousSibling(getter_AddRefs(xpAccessibleResult
));
935 xpAccessibleStart
->GetAccessibleToRight(getter_AddRefs(xpAccessibleResult
));
938 xpAccessibleStart
->GetAccessibleAbove(getter_AddRefs(xpAccessibleResult
));
941 // MSAA relationship extensions to accNavigate
942 case NAVRELATION_CONTROLLED_BY
:
943 xpRelation
= nsIAccessibleRelation::RELATION_CONTROLLED_BY
;
945 case NAVRELATION_CONTROLLER_FOR
:
946 xpRelation
= nsIAccessibleRelation::RELATION_CONTROLLER_FOR
;
948 case NAVRELATION_LABEL_FOR
:
949 xpRelation
= nsIAccessibleRelation::RELATION_LABEL_FOR
;
951 case NAVRELATION_LABELLED_BY
:
952 xpRelation
= nsIAccessibleRelation::RELATION_LABELLED_BY
;
954 case NAVRELATION_MEMBER_OF
:
955 xpRelation
= nsIAccessibleRelation::RELATION_MEMBER_OF
;
957 case NAVRELATION_NODE_CHILD_OF
:
958 xpRelation
= nsIAccessibleRelation::RELATION_NODE_CHILD_OF
;
960 case NAVRELATION_FLOWS_TO
:
961 xpRelation
= nsIAccessibleRelation::RELATION_FLOWS_TO
;
963 case NAVRELATION_FLOWS_FROM
:
964 xpRelation
= nsIAccessibleRelation::RELATION_FLOWS_FROM
;
966 case NAVRELATION_SUBWINDOW_OF
:
967 xpRelation
= nsIAccessibleRelation::RELATION_SUBWINDOW_OF
;
969 case NAVRELATION_EMBEDS
:
970 xpRelation
= nsIAccessibleRelation::RELATION_EMBEDS
;
972 case NAVRELATION_EMBEDDED_BY
:
973 xpRelation
= nsIAccessibleRelation::RELATION_EMBEDDED_BY
;
975 case NAVRELATION_POPUP_FOR
:
976 xpRelation
= nsIAccessibleRelation::RELATION_POPUP_FOR
;
978 case NAVRELATION_PARENT_WINDOW_OF
:
979 xpRelation
= nsIAccessibleRelation::RELATION_PARENT_WINDOW_OF
;
981 case NAVRELATION_DEFAULT_BUTTON
:
982 xpRelation
= nsIAccessibleRelation::RELATION_DEFAULT_BUTTON
;
984 case NAVRELATION_DESCRIBED_BY
:
985 xpRelation
= nsIAccessibleRelation::RELATION_DESCRIBED_BY
;
987 case NAVRELATION_DESCRIPTION_FOR
:
988 xpRelation
= nsIAccessibleRelation::RELATION_DESCRIPTION_FOR
;
992 pvarEndUpAt
->vt
= VT_EMPTY
;
995 nsresult rv
= GetAccessibleRelated(xpRelation
,
996 getter_AddRefs(xpAccessibleResult
));
997 if (rv
== NS_ERROR_NOT_IMPLEMENTED
) {
1002 if (xpAccessibleResult
) {
1003 pvarEndUpAt
->pdispVal
= NativeAccessible(xpAccessibleResult
);
1004 pvarEndUpAt
->vt
= VT_DISPATCH
;
1007 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1011 STDMETHODIMP
nsAccessibleWrap::accHitTest(
1012 /* [in] */ long xLeft
,
1013 /* [in] */ long yTop
,
1014 /* [retval][out] */ VARIANT __RPC_FAR
*pvarChild
)
1017 VariantInit(pvarChild
);
1019 // convert to window coords
1020 nsCOMPtr
<nsIAccessible
> xpAccessible
;
1025 if (MustPrune(this)) {
1026 xpAccessible
= this;
1029 GetChildAtPoint(xLeft
, yTop
, getter_AddRefs(xpAccessible
));
1032 // if we got a child
1034 // if the child is us
1035 if (xpAccessible
== static_cast<nsIAccessible
*>(this)) {
1036 pvarChild
->vt
= VT_I4
;
1037 pvarChild
->lVal
= CHILDID_SELF
;
1038 } else { // its not create an Accessible for it.
1039 pvarChild
->vt
= VT_DISPATCH
;
1040 pvarChild
->pdispVal
= NativeAccessible(xpAccessible
);
1041 nsCOMPtr
<nsIAccessNode
> accessNode(do_QueryInterface(xpAccessible
));
1042 NS_ASSERTION(accessNode
, "Unable to QI to nsIAccessNode");
1043 nsCOMPtr
<nsIDOMNode
> domNode
;
1044 accessNode
->GetDOMNode(getter_AddRefs(domNode
));
1046 // Has already been shut down
1047 pvarChild
->vt
= VT_EMPTY
;
1052 // no child at that point
1053 pvarChild
->vt
= VT_EMPTY
;
1056 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1061 STDMETHODIMP
nsAccessibleWrap::accDoDefaultAction(
1062 /* [optional][in] */ VARIANT varChild
)
1065 nsCOMPtr
<nsIAccessible
> xpAccessible
;
1066 GetXPAccessibleFor(varChild
, getter_AddRefs(xpAccessible
));
1068 if (!xpAccessible
|| FAILED(xpAccessible
->DoAction(0))) {
1071 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1075 STDMETHODIMP
nsAccessibleWrap::put_accName(
1076 /* [optional][in] */ VARIANT varChild
,
1077 /* [in] */ BSTR szName
)
1082 STDMETHODIMP
nsAccessibleWrap::put_accValue(
1083 /* [optional][in] */ VARIANT varChild
,
1084 /* [in] */ BSTR szValue
)
1091 ////////////////////////////////////////////////////////////////////////////////
1092 // nsAccessibleWrap. IEnumVariant
1095 nsAccessibleWrap::Next(ULONG aNumElementsRequested
, VARIANT FAR
* aPVar
,
1096 ULONG FAR
* aNumElementsFetched
)
1098 // Children already cached via QI to IEnumVARIANT
1100 *aNumElementsFetched
= 0;
1102 if (aNumElementsRequested
<= 0 || !aPVar
)
1103 return E_INVALIDARG
;
1105 if (mEnumVARIANTPosition
== kIEnumVariantDisconnected
)
1106 return CO_E_OBJNOTCONNECTED
;
1108 nsCOMPtr
<nsIAccessible
> traversedAcc
;
1109 nsresult rv
= GetChildAt(mEnumVARIANTPosition
, getter_AddRefs(traversedAcc
));
1113 for (PRUint32 i
= 0; i
< aNumElementsRequested
; i
++) {
1114 VariantInit(&aPVar
[i
]);
1116 aPVar
[i
].pdispVal
= NativeAccessible(traversedAcc
);
1117 aPVar
[i
].vt
= VT_DISPATCH
;
1118 (*aNumElementsFetched
)++;
1120 nsCOMPtr
<nsIAccessible
> nextAcc
;
1121 traversedAcc
->GetNextSibling(getter_AddRefs(nextAcc
));
1125 traversedAcc
= nextAcc
;
1128 mEnumVARIANTPosition
+= *aNumElementsFetched
;
1129 return (*aNumElementsFetched
) < aNumElementsRequested
? S_FALSE
: S_OK
;
1131 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1136 nsAccessibleWrap::Skip(ULONG aNumElements
)
1139 if (mEnumVARIANTPosition
== kIEnumVariantDisconnected
)
1140 return CO_E_OBJNOTCONNECTED
;
1142 mEnumVARIANTPosition
+= aNumElements
;
1144 PRInt32 numChildren
;
1145 GetChildCount(&numChildren
);
1147 if (mEnumVARIANTPosition
> numChildren
)
1149 mEnumVARIANTPosition
= numChildren
;
1152 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1157 nsAccessibleWrap::Reset(void)
1159 mEnumVARIANTPosition
= 0;
1164 nsAccessibleWrap::Clone(IEnumVARIANT FAR
* FAR
* ppenum
)
1169 nsCOMPtr
<nsIArray
> childArray
;
1170 nsresult rv
= GetChildren(getter_AddRefs(childArray
));
1172 *ppenum
= new AccessibleEnumerator(childArray
);
1174 return E_OUTOFMEMORY
;
1177 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1181 ////////////////////////////////////////////////////////////////////////////////
1182 // nsAccessibleWrap. IAccessible2
1185 nsAccessibleWrap::get_nRelations(long *aNRelations
)
1189 nsresult rv
= GetRelationsCount(&count
);
1190 *aNRelations
= count
;
1192 return GetHRESULT(rv
);
1194 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1199 nsAccessibleWrap::get_relation(long aRelationIndex
,
1200 IAccessibleRelation
**aRelation
)
1205 nsCOMPtr
<nsIAccessibleRelation
> relation
;
1206 nsresult rv
= GetRelation(aRelationIndex
, getter_AddRefs(relation
));
1208 return GetHRESULT(rv
);
1210 nsCOMPtr
<nsIWinAccessNode
> winAccessNode(do_QueryInterface(relation
));
1214 void *instancePtr
= NULL
;
1215 rv
= winAccessNode
->QueryNativeInterface(IID_IAccessibleRelation
,
1218 return GetHRESULT(rv
);
1220 *aRelation
= static_cast<IAccessibleRelation
*>(instancePtr
);
1223 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1228 nsAccessibleWrap::get_relations(long aMaxRelations
,
1229 IAccessibleRelation
**aRelation
,
1236 nsCOMPtr
<nsIArray
> relations
;
1237 nsresult rv
= GetRelations(getter_AddRefs(relations
));
1239 return GetHRESULT(rv
);
1241 PRUint32 length
= 0;
1242 rv
= relations
->GetLength(&length
);
1244 return GetHRESULT(rv
);
1249 PRUint32 count
= length
< (PRUint32
)aMaxRelations
? length
: aMaxRelations
;
1252 for (; index
< count
; index
++) {
1253 nsCOMPtr
<nsIWinAccessNode
> winAccessNode
=
1254 do_QueryElementAt(relations
, index
, &rv
);
1258 void *instancePtr
= NULL
;
1259 nsresult rv
= winAccessNode
->QueryNativeInterface(IID_IAccessibleRelation
,
1264 aRelation
[index
] = static_cast<IAccessibleRelation
*>(instancePtr
);
1267 if (NS_FAILED(rv
)) {
1268 for (PRUint32 index2
= 0; index2
< index
; index2
++) {
1269 aRelation
[index2
]->Release();
1270 aRelation
[index2
] = NULL
;
1272 return GetHRESULT(rv
);
1275 *aNRelations
= count
;
1278 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1283 nsAccessibleWrap::role(long *aRole
)
1288 PRUint32 xpRole
= 0;
1289 nsresult rv
= GetFinalRole(&xpRole
);
1291 return GetHRESULT(rv
);
1293 NS_ASSERTION(gWindowsRoleMap
[nsIAccessibleRole::ROLE_LAST_ENTRY
].ia2Role
== ROLE_WINDOWS_LAST_ENTRY
,
1294 "MSAA role map skewed");
1296 *aRole
= gWindowsRoleMap
[xpRole
].ia2Role
;
1299 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1304 nsAccessibleWrap::scrollTo(enum IA2ScrollType aScrollType
)
1307 nsresult rv
= ScrollTo(aScrollType
);
1308 return GetHRESULT(rv
);
1310 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1315 nsAccessibleWrap::scrollToPoint(enum IA2CoordinateType aCoordType
,
1319 PRUint32 geckoCoordType
= (aCoordType
== IA2_COORDTYPE_SCREEN_RELATIVE
) ?
1320 nsIAccessibleCoordinateType::COORDTYPE_SCREEN_RELATIVE
:
1321 nsIAccessibleCoordinateType::COORDTYPE_PARENT_RELATIVE
;
1323 nsresult rv
= ScrollToPoint(geckoCoordType
, aX
, aY
);
1324 return GetHRESULT(rv
);
1326 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1331 nsAccessibleWrap::get_groupPosition(long *aGroupLevel
,
1332 long *aSimilarItemsInGroup
,
1333 long *aPositionInGroup
)
1336 PRInt32 groupLevel
= 0;
1337 PRInt32 similarItemsInGroup
= 0;
1338 PRInt32 positionInGroup
= 0;
1339 nsresult rv
= GroupPosition(&groupLevel
, &similarItemsInGroup
,
1342 *aGroupLevel
= groupLevel
;
1343 *aSimilarItemsInGroup
= similarItemsInGroup
;
1344 *aPositionInGroup
= positionInGroup
;
1347 return GetHRESULT(rv
);
1349 if (groupLevel
==0 && similarItemsInGroup
== 0 && positionInGroup
== 0)
1353 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1358 nsAccessibleWrap::get_states(AccessibleStates
*aStates
)
1363 // XXX: bug 344674 should come with better approach that we have here.
1365 PRUint32 states
= 0, extraStates
= 0;
1366 nsresult rv
= GetFinalState(&states
, &extraStates
);
1368 return GetHRESULT(rv
);
1370 if (states
& nsIAccessibleStates::STATE_INVALID
)
1371 *aStates
|= IA2_STATE_INVALID_ENTRY
;
1372 if (states
& nsIAccessibleStates::STATE_REQUIRED
)
1373 *aStates
|= IA2_STATE_REQUIRED
;
1375 // The following IA2 states are not supported by Gecko
1377 // IA2_STATE_MANAGES_DESCENDANTS
1378 // IA2_STATE_ICONIFIED
1379 // IA2_STATE_INVALID // This is not a state, it is the absence of a state
1381 if (extraStates
& nsIAccessibleStates::EXT_STATE_ACTIVE
)
1382 *aStates
|= IA2_STATE_ACTIVE
;
1383 if (extraStates
& nsIAccessibleStates::EXT_STATE_DEFUNCT
)
1384 *aStates
|= IA2_STATE_DEFUNCT
;
1385 if (extraStates
& nsIAccessibleStates::EXT_STATE_EDITABLE
)
1386 *aStates
|= IA2_STATE_EDITABLE
;
1387 if (extraStates
& nsIAccessibleStates::EXT_STATE_HORIZONTAL
)
1388 *aStates
|= IA2_STATE_HORIZONTAL
;
1389 if (extraStates
& nsIAccessibleStates::EXT_STATE_MODAL
)
1390 *aStates
|= IA2_STATE_MODAL
;
1391 if (extraStates
& nsIAccessibleStates::EXT_STATE_MULTI_LINE
)
1392 *aStates
|= IA2_STATE_MULTI_LINE
;
1393 if (extraStates
& nsIAccessibleStates::EXT_STATE_OPAQUE
)
1394 *aStates
|= IA2_STATE_OPAQUE
;
1395 if (extraStates
& nsIAccessibleStates::EXT_STATE_SELECTABLE_TEXT
)
1396 *aStates
|= IA2_STATE_SELECTABLE_TEXT
;
1397 if (extraStates
& nsIAccessibleStates::EXT_STATE_SINGLE_LINE
)
1398 *aStates
|= IA2_STATE_SINGLE_LINE
;
1399 if (extraStates
& nsIAccessibleStates::EXT_STATE_STALE
)
1400 *aStates
|= IA2_STATE_STALE
;
1401 if (extraStates
& nsIAccessibleStates::EXT_STATE_SUPPORTS_AUTOCOMPLETION
)
1402 *aStates
|= IA2_STATE_SUPPORTS_AUTOCOMPLETION
;
1403 if (extraStates
& nsIAccessibleStates::EXT_STATE_TRANSIENT
)
1404 *aStates
|= IA2_STATE_TRANSIENT
;
1405 if (extraStates
& nsIAccessibleStates::EXT_STATE_VERTICAL
)
1406 *aStates
|= IA2_STATE_VERTICAL
;
1410 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1415 nsAccessibleWrap::get_extendedRole(BSTR
*aExtendedRole
)
1418 *aExtendedRole
= NULL
;
1419 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1425 nsAccessibleWrap::get_localizedExtendedRole(BSTR
*aLocalizedExtendedRole
)
1428 *aLocalizedExtendedRole
= NULL
;
1429 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1435 nsAccessibleWrap::get_nExtendedStates(long *aNExtendedStates
)
1438 *aNExtendedStates
= 0;
1439 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1445 nsAccessibleWrap::get_extendedStates(long aMaxExtendedStates
,
1446 BSTR
**aExtendedStates
,
1447 long *aNExtendedStates
)
1450 *aExtendedStates
= NULL
;
1451 *aNExtendedStates
= 0;
1452 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1458 nsAccessibleWrap::get_localizedExtendedStates(long aMaxLocalizedExtendedStates
,
1459 BSTR
**aLocalizedExtendedStates
,
1460 long *aNLocalizedExtendedStates
)
1463 *aLocalizedExtendedStates
= NULL
;
1464 *aNLocalizedExtendedStates
= 0;
1465 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1471 nsAccessibleWrap::get_uniqueID(long *uniqueID
)
1475 nsresult rv
= GetUniqueID(&id
);
1477 return GetHRESULT(rv
);
1479 *uniqueID
= - reinterpret_cast<long>(id
);
1482 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1487 nsAccessibleWrap::get_windowHandle(HWND
*aWindowHandle
)
1495 void *handle
= nsnull
;
1496 nsresult rv
= GetOwnerWindow(&handle
);
1498 return GetHRESULT(rv
);
1500 *aWindowHandle
= reinterpret_cast<HWND
>(handle
);
1503 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1508 nsAccessibleWrap::get_indexInParent(long *aIndexInParent
)
1511 *aIndexInParent
= -1;
1514 nsresult rv
= GetIndexInParent(&index
);
1516 return GetHRESULT(rv
);
1521 *aIndexInParent
= index
;
1524 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1529 nsAccessibleWrap::get_locale(IA2Locale
*aLocale
)
1532 // Language codes consist of a primary code and a possibly empty series of
1533 // subcodes: language-code = primary-code ( "-" subcode )*
1534 // Two-letter primary codes are reserved for [ISO639] language abbreviations.
1535 // Any two-letter subcode is understood to be a [ISO3166] country code.
1538 nsresult rv
= GetLanguage(lang
);
1540 return GetHRESULT(rv
);
1542 // If primary code consists from two letters then expose it as language.
1543 PRInt32 offset
= lang
.FindChar('-', 0);
1545 if (lang
.Length() == 2) {
1546 aLocale
->language
= ::SysAllocString(lang
.get());
1549 } else if (offset
== 2) {
1550 aLocale
->language
= ::SysAllocStringLen(lang
.get(), 2);
1552 // If the first subcode consists from two letters then expose it as
1554 offset
= lang
.FindChar('-', 3);
1556 if (lang
.Length() == 5) {
1557 aLocale
->country
= ::SysAllocString(lang
.get() + 3);
1560 } else if (offset
== 5) {
1561 aLocale
->country
= ::SysAllocStringLen(lang
.get() + 3, 2);
1565 // Expose as a string if primary code or subcode cannot point to language or
1566 // country abbreviations or if there are more than one subcode.
1567 aLocale
->variant
= ::SysAllocString(lang
.get());
1570 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1575 nsAccessibleWrap::get_attributes(BSTR
*aAttributes
)
1577 // The format is name:value;name:value; with \ for escaping these
1578 // characters ":;=,\".
1580 *aAttributes
= NULL
;
1582 nsCOMPtr
<nsIPersistentProperties
> attributes
;
1583 nsresult rv
= GetAttributes(getter_AddRefs(attributes
));
1585 return GetHRESULT(rv
);
1587 return ConvertToIA2Attributes(attributes
, aAttributes
);
1589 } __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
1593 // For IDispatch support
1595 nsAccessibleWrap::GetTypeInfoCount(UINT
*p
)
1601 // For IDispatch support
1602 STDMETHODIMP
nsAccessibleWrap::GetTypeInfo(UINT i
, LCID lcid
, ITypeInfo
**ppti
)
1608 // For IDispatch support
1610 nsAccessibleWrap::GetIDsOfNames(REFIID riid
, LPOLESTR
*rgszNames
,
1611 UINT cNames
, LCID lcid
, DISPID
*rgDispId
)
1616 // For IDispatch support
1617 STDMETHODIMP
nsAccessibleWrap::Invoke(DISPID dispIdMember
, REFIID riid
,
1618 LCID lcid
, WORD wFlags
, DISPPARAMS
*pDispParams
,
1619 VARIANT
*pVarResult
, EXCEPINFO
*pExcepInfo
, UINT
*puArgErr
)
1625 NS_IMETHODIMP
nsAccessibleWrap::GetNativeInterface(void **aOutAccessible
)
1627 *aOutAccessible
= static_cast<IAccessible
*>(this);
1635 nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent
*aEvent
)
1637 NS_ENSURE_ARG(aEvent
);
1639 nsresult rv
= nsAccessible::FireAccessibleEvent(aEvent
);
1640 NS_ENSURE_SUCCESS(rv
, rv
);
1642 return FirePlatformEvent(aEvent
);
1646 nsAccessibleWrap::FirePlatformEvent(nsIAccessibleEvent
*aEvent
)
1648 PRUint32 eventType
= 0;
1649 aEvent
->GetEventType(&eventType
);
1651 NS_ENSURE_TRUE(eventType
> 0 &&
1652 eventType
< nsIAccessibleEvent::EVENT_LAST_ENTRY
,
1655 PRUint32 winLastEntry
= gWinEventMap
[nsIAccessibleEvent::EVENT_LAST_ENTRY
];
1656 NS_ASSERTION(winLastEntry
== kEVENT_LAST_ENTRY
,
1657 "MSAA event map skewed");
1659 PRUint32 winEvent
= gWinEventMap
[eventType
];
1663 // Means we're not active.
1664 NS_ENSURE_TRUE(mWeakShell
, NS_ERROR_FAILURE
);
1666 nsCOMPtr
<nsIAccessible
> accessible
;
1667 aEvent
->GetAccessible(getter_AddRefs(accessible
));
1671 if (eventType
== nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED
||
1672 eventType
== nsIAccessibleEvent::EVENT_FOCUS
) {
1673 UpdateSystemCaret();
1676 PRInt32 childID
= GetChildIDFor(accessible
); // get the id for the accessible
1678 return NS_OK
; // Can't fire an event without a child ID
1680 // See if we're in a scrollable area with its own window
1681 nsCOMPtr
<nsIAccessible
> newAccessible
;
1682 if (eventType
== nsIAccessibleEvent::EVENT_ASYNCH_HIDE
||
1683 eventType
== nsIAccessibleEvent::EVENT_DOM_DESTROY
) {
1684 // Don't use frame from current accessible when we're hiding that
1686 accessible
->GetParent(getter_AddRefs(newAccessible
));
1688 newAccessible
= accessible
;
1691 HWND hWnd
= GetHWNDFor(newAccessible
);
1692 NS_ENSURE_TRUE(hWnd
, NS_ERROR_FAILURE
);
1694 // Gecko uses two windows for every scrollable area. One window contains
1695 // scrollbars and the child window contains only the client area.
1696 // Details of the 2 window system:
1697 // * Scrollbar window: caret drawing window & return value for WindowFromAccessibleObject()
1698 // * Client area window: text drawing window & MSAA event window
1700 // Fire MSAA event for client area window.
1701 NotifyWinEvent(winEvent
, hWnd
, OBJID_CLIENT
, childID
);
1703 // If the accessible children are changed then drop the IEnumVariant current
1704 // position of the accessible.
1705 if (eventType
== nsIAccessibleEvent::EVENT_REORDER
)
1706 UnattachIEnumVariant();
1711 //------- Helper methods ---------
1713 PRInt32
nsAccessibleWrap::GetChildIDFor(nsIAccessible
* aAccessible
)
1715 // A child ID of the window is required, when we use NotifyWinEvent,
1716 // so that the 3rd party application can call back and get the IAccessible
1717 // the event occured on.
1719 void *uniqueID
= nsnull
;
1720 nsCOMPtr
<nsIAccessNode
> accessNode(do_QueryInterface(aAccessible
));
1724 accessNode
->GetUniqueID(&uniqueID
);
1726 // Yes, this means we're only compatibible with 32 bit
1727 // MSAA is only available for 32 bit windows, so it's okay
1728 return - NS_PTR_TO_INT32(uniqueID
);
1732 nsAccessibleWrap::GetHWNDFor(nsIAccessible
*aAccessible
)
1734 nsCOMPtr
<nsIAccessNode
> accessNode(do_QueryInterface(aAccessible
));
1735 nsCOMPtr
<nsPIAccessNode
> privateAccessNode(do_QueryInterface(accessNode
));
1736 if (!privateAccessNode
)
1741 nsIFrame
*frame
= privateAccessNode
->GetFrame();
1743 nsIWidget
*window
= frame
->GetWindow();
1745 window
->IsVisible(isVisible
);
1747 // Short explanation:
1748 // If HWND for frame is inside a hidden window, fire the event on the
1749 // containing document's visible window.
1751 // Long explanation:
1752 // This is really just to fix combo boxes with JAWS. Window-Eyes already
1753 // worked with combo boxes because they use the value change event in
1754 // the closed combo box case. JAWS will only pay attention to the focus
1755 // events on the list items. The JAWS developers haven't fixed that, so
1756 // we'll use the focus events to make JAWS work. However, JAWS is
1757 // ignoring events on a hidden window. So, in order to fix the bug where
1758 // JAWS doesn't echo the current option as it changes in a closed
1759 // combo box, we need to use an ensure that we never fire an event with
1760 // an HWND for a hidden window.
1761 hWnd
= (HWND
)frame
->GetWindow()->GetNativeData(NS_NATIVE_WINDOW
);
1766 void* handle
= nsnull
;
1767 nsCOMPtr
<nsIAccessibleDocument
> accessibleDoc
;
1768 accessNode
->GetAccessibleDocument(getter_AddRefs(accessibleDoc
));
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
;
1874 void nsAccessibleWrap::GetXPAccessibleFor(const VARIANT
& aVarChild
, nsIAccessible
**aXPAccessible
)
1876 *aXPAccessible
= nsnull
;
1878 return; // Fail, we don't want to do anything after we've shut down
1880 // if its us real easy - this seems to always be the case
1881 if (aVarChild
.lVal
== CHILDID_SELF
) {
1882 *aXPAccessible
= static_cast<nsIAccessible
*>(this);
1884 else if (MustPrune(this)) {
1888 // XXX It is rare to use a VARIANT with a child num
1889 // so optimizing this is not a priority
1890 // We can come back it do it later, if there are perf problems
1891 // with a specific assistive technology
1892 nsCOMPtr
<nsIAccessible
> xpAccessible
, nextAccessible
;
1893 GetFirstChild(getter_AddRefs(xpAccessible
));
1894 for (PRInt32 index
= 0; xpAccessible
; index
++) {
1897 if (aVarChild
.lVal
== index
) {
1898 *aXPAccessible
= xpAccessible
;
1901 nextAccessible
= xpAccessible
;
1902 nextAccessible
->GetNextSibling(getter_AddRefs(xpAccessible
));
1905 NS_IF_ADDREF(*aXPAccessible
);
1908 void nsAccessibleWrap::UpdateSystemCaret()
1910 // Move the system caret so that Windows Tablet Edition and tradional ATs with
1911 // off-screen model can follow the caret
1914 nsRefPtr
<nsRootAccessible
> rootAccessible
= GetRootAccessible();
1915 if (!rootAccessible
) {
1919 nsRefPtr
<nsCaretAccessible
> caretAccessible
= rootAccessible
->GetCaretAccessible();
1920 if (!caretAccessible
) {
1925 nsRect caretRect
= caretAccessible
->GetCaretRect(&widget
);
1927 if (caretRect
.IsEmpty() || !(caretWnd
= (HWND
)widget
->GetNativeData(NS_NATIVE_WINDOW
))) {
1931 // Create invisible bitmap for caret, otherwise its appearance interferes
1933 HBITMAP caretBitMap
= CreateBitmap(1, caretRect
.height
, 1, 1, NULL
);
1934 if (::CreateCaret(caretWnd
, caretBitMap
, 1, caretRect
.height
)) { // Also destroys the last caret
1935 ::ShowCaret(caretWnd
);
1937 ::GetWindowRect(caretWnd
, &windowRect
);
1938 ::SetCaretPos(caretRect
.x
- windowRect
.left
, caretRect
.y
- windowRect
.top
);
1939 ::DeleteObject(caretBitMap
);