2003-04-01 20:02:51 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2003
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
2004-04-17 21:52:36 +00:00
|
|
|
* Original Author: Aaron Leventhal (aaronl@netscape.com)
|
2003-04-01 20:02:51 +00:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
2004-04-17 21:52:36 +00:00
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
2003-04-01 20:02:51 +00:00
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include "nsAccessibleWrap.h"
|
2005-01-21 03:50:26 +00:00
|
|
|
#include "nsAccessibilityAtoms.h"
|
2007-04-16 20:23:00 +00:00
|
|
|
|
|
|
|
#include "nsIAccessibleDocument.h"
|
2003-04-01 20:02:51 +00:00
|
|
|
#include "nsIAccessibleSelectable.h"
|
2007-04-16 20:23:00 +00:00
|
|
|
#include "nsIAccessibleEvent.h"
|
2003-04-01 20:02:51 +00:00
|
|
|
#include "nsIAccessibleWin32Object.h"
|
2007-03-18 05:21:13 +00:00
|
|
|
|
|
|
|
#include "Accessible2_i.c"
|
|
|
|
#include "AccessibleAction_i.c"
|
2007-03-18 15:54:48 +00:00
|
|
|
#include "AccessibleStates.h"
|
2007-03-18 05:21:13 +00:00
|
|
|
|
2006-04-12 15:43:32 +00:00
|
|
|
#include "nsIMutableArray.h"
|
2004-05-25 14:37:07 +00:00
|
|
|
#include "nsIDOMDocument.h"
|
2005-03-02 19:05:09 +00:00
|
|
|
#include "nsIFrame.h"
|
2005-08-18 16:35:49 +00:00
|
|
|
#include "nsIScrollableFrame.h"
|
2005-03-02 19:05:09 +00:00
|
|
|
#include "nsINameSpaceManager.h"
|
2005-01-21 03:50:26 +00:00
|
|
|
#include "nsINodeInfo.h"
|
2004-05-25 14:37:07 +00:00
|
|
|
#include "nsIPrefService.h"
|
|
|
|
#include "nsIServiceManager.h"
|
2005-03-27 03:29:53 +00:00
|
|
|
#include "nsTextFormatter.h"
|
2005-03-02 19:05:09 +00:00
|
|
|
#include "nsIView.h"
|
2006-07-17 14:53:36 +00:00
|
|
|
#include "nsRoleMap.h"
|
2007-04-16 20:23:00 +00:00
|
|
|
#include "nsEventMap.h"
|
2007-01-20 12:43:08 +00:00
|
|
|
#include "nsArrayUtils.h"
|
2003-04-01 20:02:51 +00:00
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
/* For documentation of the accessibility architecture,
|
2003-04-01 20:02:51 +00:00
|
|
|
* see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
|
|
|
|
*/
|
|
|
|
|
|
|
|
//#define DEBUG_LEAKS
|
|
|
|
|
|
|
|
#ifdef DEBUG_LEAKS
|
|
|
|
static gAccessibles = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
EXTERN_C GUID CDECL CLSID_Accessible =
|
|
|
|
{ 0x61044601, 0xa811, 0x4e2b, { 0xbb, 0xba, 0x17, 0xbf, 0xab, 0xd3, 0x29, 0xd7 } };
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Class nsAccessibleWrap
|
|
|
|
*/
|
|
|
|
|
|
|
|
//-----------------------------------------------------
|
2006-02-28 14:35:50 +00:00
|
|
|
// construction
|
2003-04-01 20:02:51 +00:00
|
|
|
//-----------------------------------------------------
|
2006-02-28 14:35:50 +00:00
|
|
|
nsAccessibleWrap::nsAccessibleWrap(nsIDOMNode* aNode, nsIWeakReference *aShell):
|
2003-05-15 08:37:38 +00:00
|
|
|
nsAccessible(aNode, aShell), mEnumVARIANTPosition(0)
|
2003-04-01 20:02:51 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------
|
|
|
|
// destruction
|
|
|
|
//-----------------------------------------------------
|
|
|
|
nsAccessibleWrap::~nsAccessibleWrap()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------
|
|
|
|
// IUnknown interface methods - see iunknown.h for documentation
|
|
|
|
//-----------------------------------------------------
|
|
|
|
STDMETHODIMP_(ULONG) nsAccessibleWrap::AddRef()
|
|
|
|
{
|
|
|
|
return nsAccessNode::AddRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP_(ULONG) nsAccessibleWrap::Release()
|
|
|
|
{
|
|
|
|
return nsAccessNode::Release();
|
|
|
|
}
|
|
|
|
|
2003-04-15 08:45:55 +00:00
|
|
|
// Microsoft COM QueryInterface
|
2003-04-01 20:02:51 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::QueryInterface(REFIID iid, void** ppv)
|
|
|
|
{
|
|
|
|
*ppv = NULL;
|
|
|
|
|
|
|
|
if (IID_IUnknown == iid || IID_IDispatch == iid || IID_IAccessible == iid)
|
|
|
|
*ppv = NS_STATIC_CAST(IAccessible*, this);
|
|
|
|
else if (IID_IEnumVARIANT == iid && !gIsEnumVariantSupportDisabled) {
|
2006-07-12 13:14:53 +00:00
|
|
|
long numChildren;
|
|
|
|
get_accChildCount(&numChildren);
|
2003-04-15 08:45:55 +00:00
|
|
|
if (numChildren > 0) // Don't support this interface for leaf elements
|
2003-04-01 20:02:51 +00:00
|
|
|
*ppv = NS_STATIC_CAST(IEnumVARIANT*, this);
|
2007-03-18 05:21:13 +00:00
|
|
|
} else if (IID_IServiceProvider == iid)
|
2003-04-01 20:02:51 +00:00
|
|
|
*ppv = NS_STATIC_CAST(IServiceProvider*, this);
|
2007-04-08 03:58:08 +00:00
|
|
|
else if (IID_IAccessible2 == iid)
|
|
|
|
*ppv = NS_STATIC_CAST(IAccessible2*, this);
|
2007-03-18 05:21:13 +00:00
|
|
|
else if (IID_IAccessibleAction == iid)
|
|
|
|
*ppv = NS_STATIC_CAST(IAccessibleAction*, this);
|
2003-04-01 20:02:51 +00:00
|
|
|
|
|
|
|
if (NULL == *ppv)
|
|
|
|
return nsAccessNodeWrap::QueryInterface(iid, ppv);
|
2006-02-28 14:35:50 +00:00
|
|
|
|
2003-04-01 20:02:51 +00:00
|
|
|
(NS_REINTERPRET_CAST(IUnknown*, *ppv))->AddRef();
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------
|
|
|
|
// IAccessible methods
|
|
|
|
//-----------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
STDMETHODIMP nsAccessibleWrap::AccessibleObjectFromWindow(HWND hwnd,
|
|
|
|
DWORD dwObjectID,
|
|
|
|
REFIID riid,
|
|
|
|
void **ppvObject)
|
|
|
|
{
|
|
|
|
// open the dll dynamically
|
2006-02-28 14:35:50 +00:00
|
|
|
if (!gmAccLib)
|
|
|
|
gmAccLib =::LoadLibrary("OLEACC.DLL");
|
2003-04-01 20:02:51 +00:00
|
|
|
|
|
|
|
if (gmAccLib) {
|
|
|
|
if (!gmAccessibleObjectFromWindow)
|
|
|
|
gmAccessibleObjectFromWindow = (LPFNACCESSIBLEOBJECTFROMWINDOW)GetProcAddress(gmAccLib,"AccessibleObjectFromWindow");
|
|
|
|
|
|
|
|
if (gmAccessibleObjectFromWindow)
|
|
|
|
return gmAccessibleObjectFromWindow(hwnd, dwObjectID, riid, ppvObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP nsAccessibleWrap::NotifyWinEvent(DWORD event,
|
|
|
|
HWND hwnd,
|
|
|
|
LONG idObjectType,
|
|
|
|
LONG idObject)
|
|
|
|
{
|
|
|
|
if (gmNotifyWinEvent)
|
|
|
|
return gmNotifyWinEvent(event, hwnd, idObjectType, idObject);
|
2006-02-28 14:35:50 +00:00
|
|
|
|
2003-04-01 20:02:51 +00:00
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP nsAccessibleWrap::get_accParent( IDispatch __RPC_FAR *__RPC_FAR *ppdispParent)
|
|
|
|
{
|
2003-04-15 08:45:55 +00:00
|
|
|
*ppdispParent = NULL;
|
|
|
|
if (!mWeakShell)
|
|
|
|
return E_FAIL; // We've been shut down
|
|
|
|
|
2005-03-02 19:05:09 +00:00
|
|
|
nsIFrame *frame = GetFrame();
|
2005-08-18 16:35:49 +00:00
|
|
|
HWND hwnd = 0;
|
2005-03-23 14:01:27 +00:00
|
|
|
if (frame) {
|
2005-08-18 16:35:49 +00:00
|
|
|
nsIView *view = frame->GetViewExternal();
|
|
|
|
if (view) {
|
2005-03-23 14:01:27 +00:00
|
|
|
// This code is essentially our implementation of WindowFromAccessibleObject,
|
|
|
|
// because MSAA iterates get_accParent() until it sees an object of ROLE_WINDOW
|
2006-02-28 14:35:50 +00:00
|
|
|
// to know where the window for a given accessible is. We must expose the native
|
2005-03-23 14:01:27 +00:00
|
|
|
// window accessible that MSAA creates for us. This must be done for the document
|
|
|
|
// object as well as any layout that creates its own window (e.g. via overflow: scroll)
|
2005-08-18 16:35:49 +00:00
|
|
|
nsIWidget *widget = view->GetWidget();
|
|
|
|
if (widget) {
|
|
|
|
hwnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW);
|
|
|
|
NS_ASSERTION(hwnd, "No window handle for window");
|
2005-08-19 03:21:38 +00:00
|
|
|
nsIView *rootView;
|
|
|
|
view->GetViewManager()->GetRootView(rootView);
|
|
|
|
if (rootView == view) {
|
|
|
|
// If the current object has a widget but was created by an
|
|
|
|
// outer object with its own outer window, then
|
|
|
|
// we want the native accessible for that outer window
|
|
|
|
hwnd = ::GetParent(hwnd);
|
|
|
|
NS_ASSERTION(hwnd, "No window handle for window");
|
|
|
|
}
|
2005-03-23 14:01:27 +00:00
|
|
|
}
|
2005-08-18 16:35:49 +00:00
|
|
|
else {
|
2005-08-19 03:21:38 +00:00
|
|
|
// If a frame is a scrollable frame, then it has one window for the client area,
|
|
|
|
// not an extra parent window for just the scrollbars
|
2005-08-18 16:35:49 +00:00
|
|
|
nsIScrollableFrame *scrollFrame = nsnull;
|
|
|
|
CallQueryInterface(frame, &scrollFrame);
|
|
|
|
if (scrollFrame) {
|
|
|
|
hwnd = (HWND)scrollFrame->GetScrolledFrame()->GetWindow()->GetNativeData(NS_NATIVE_WINDOW);
|
|
|
|
NS_ASSERTION(hwnd, "No window handle for window");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hwnd && SUCCEEDED(AccessibleObjectFromWindow(hwnd, OBJID_WINDOW, IID_IAccessible,
|
|
|
|
(void**)ppdispParent))) {
|
|
|
|
return S_OK;
|
2005-03-02 19:05:09 +00:00
|
|
|
}
|
2003-04-01 20:02:51 +00:00
|
|
|
}
|
|
|
|
|
2006-10-23 09:45:34 +00:00
|
|
|
nsCOMPtr<nsIAccessible> xpParentAccessible(GetParent());
|
2005-03-02 19:05:09 +00:00
|
|
|
NS_ASSERTION(xpParentAccessible, "No parent accessible where we're not direct child of window");
|
2005-08-18 16:35:49 +00:00
|
|
|
if (!xpParentAccessible) {
|
|
|
|
return E_UNEXPECTED;
|
|
|
|
}
|
2005-03-02 19:05:09 +00:00
|
|
|
*ppdispParent = NativeAccessible(xpParentAccessible);
|
|
|
|
|
|
|
|
return S_OK;
|
2003-04-01 20:02:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP nsAccessibleWrap::get_accChildCount( long __RPC_FAR *pcountChildren)
|
|
|
|
{
|
2006-07-12 13:14:53 +00:00
|
|
|
*pcountChildren = 0;
|
|
|
|
if (MustPrune(this)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2003-04-15 08:45:55 +00:00
|
|
|
PRInt32 numChildren;
|
2003-07-31 08:09:39 +00:00
|
|
|
GetChildCount(&numChildren);
|
2003-04-15 08:45:55 +00:00
|
|
|
*pcountChildren = numChildren;
|
2003-04-01 20:02:51 +00:00
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::get_accChild(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [in] */ VARIANT varChild,
|
|
|
|
/* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispChild)
|
|
|
|
{
|
|
|
|
*ppdispChild = NULL;
|
|
|
|
|
2003-04-15 08:45:55 +00:00
|
|
|
if (!mWeakShell || varChild.vt != VT_I4)
|
2003-04-01 20:02:51 +00:00
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
if (varChild.lVal == CHILDID_SELF) {
|
2003-04-15 08:45:55 +00:00
|
|
|
*ppdispChild = NS_STATIC_CAST(IDispatch*, this);
|
2003-04-01 20:02:51 +00:00
|
|
|
AddRef();
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2003-04-15 08:45:55 +00:00
|
|
|
nsCOMPtr<nsIAccessible> childAccessible;
|
2006-07-12 13:14:53 +00:00
|
|
|
if (!MustPrune(this)) {
|
|
|
|
GetChildAt(varChild.lVal - 1, getter_AddRefs(childAccessible));
|
|
|
|
*ppdispChild = NativeAccessible(childAccessible);
|
|
|
|
}
|
2003-04-01 20:02:51 +00:00
|
|
|
|
|
|
|
return (*ppdispChild)? S_OK: E_FAIL;
|
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::get_accName(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [optional][in] */ VARIANT varChild,
|
|
|
|
/* [retval][out] */ BSTR __RPC_FAR *pszName)
|
|
|
|
{
|
|
|
|
*pszName = NULL;
|
|
|
|
nsCOMPtr<nsIAccessible> xpAccessible;
|
|
|
|
GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
|
|
|
|
if (xpAccessible) {
|
|
|
|
nsAutoString name;
|
2003-07-31 08:09:39 +00:00
|
|
|
if (NS_FAILED(xpAccessible->GetName(name)))
|
2003-04-01 20:02:51 +00:00
|
|
|
return S_FALSE;
|
2005-03-15 15:00:44 +00:00
|
|
|
if (!name.IsVoid()) {
|
|
|
|
*pszName = ::SysAllocString(name.get());
|
|
|
|
}
|
2006-08-11 17:21:56 +00:00
|
|
|
#ifdef DEBUG_A11Y
|
2003-04-15 08:45:55 +00:00
|
|
|
NS_ASSERTION(mIsInitialized, "Access node was not initialized");
|
2006-08-11 17:21:56 +00:00
|
|
|
#endif
|
2003-04-01 20:02:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::get_accValue(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [optional][in] */ VARIANT varChild,
|
|
|
|
/* [retval][out] */ BSTR __RPC_FAR *pszValue)
|
|
|
|
{
|
|
|
|
*pszValue = NULL;
|
|
|
|
nsCOMPtr<nsIAccessible> xpAccessible;
|
|
|
|
GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
|
|
|
|
if (xpAccessible) {
|
|
|
|
nsAutoString value;
|
2006-06-15 16:55:32 +00:00
|
|
|
if (NS_FAILED(xpAccessible->GetValue(value)))
|
2003-04-01 20:02:51 +00:00
|
|
|
return S_FALSE;
|
|
|
|
|
|
|
|
*pszValue = ::SysAllocString(value.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2007-03-27 12:17:11 +00:00
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_accDescription(VARIANT varChild,
|
|
|
|
BSTR __RPC_FAR *pszDescription)
|
2005-03-27 03:29:53 +00:00
|
|
|
{
|
2007-03-27 12:17:11 +00:00
|
|
|
*pszDescription = NULL;
|
|
|
|
nsCOMPtr<nsIAccessible> xpAccessible;
|
|
|
|
GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
|
|
|
|
if (!xpAccessible)
|
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
// For items that are a choice in a list of choices, use MSAA description
|
|
|
|
// field to shoehorn positional info, it's becoming a defacto standard use for
|
|
|
|
// the field.
|
|
|
|
|
|
|
|
nsAutoString description;
|
|
|
|
|
|
|
|
// Try nsIAccessible::groupPosition to make a positional description string.
|
|
|
|
PRInt32 groupLevel;
|
|
|
|
PRInt32 similarItemsInGroup;
|
|
|
|
PRInt32 positionInGroup;
|
|
|
|
|
|
|
|
nsresult rv = xpAccessible->GroupPosition(&groupLevel, &similarItemsInGroup,
|
|
|
|
&positionInGroup);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
if (positionInGroup != -1 && similarItemsInGroup != -1) {
|
|
|
|
if (groupLevel != -1) {
|
2007-04-07 09:07:24 +00:00
|
|
|
// XXX: How do we calculate the number of children? Now we append
|
|
|
|
// " with [numChildren]c" for tree item. In the future we may need to
|
|
|
|
// use the ARIA owns property to calculate that if it's present.
|
|
|
|
PRInt32 numChildren = 0;
|
|
|
|
|
|
|
|
PRUint32 currentRole = 0;
|
|
|
|
rv = xpAccessible->GetFinalRole(¤tRole);
|
|
|
|
if (NS_SUCCEEDED(rv) &&
|
|
|
|
currentRole == nsIAccessibleRole::ROLE_OUTLINEITEM) {
|
|
|
|
nsCOMPtr<nsIAccessible> child;
|
|
|
|
xpAccessible->GetFirstChild(getter_AddRefs(child));
|
|
|
|
while (child) {
|
|
|
|
child->GetFinalRole(¤tRole);
|
|
|
|
if (currentRole == nsIAccessibleRole::ROLE_GROUPING) {
|
|
|
|
nsCOMPtr<nsIAccessible> groupChild;
|
|
|
|
child->GetFirstChild(getter_AddRefs(groupChild));
|
|
|
|
while (groupChild) {
|
|
|
|
groupChild->GetFinalRole(¤tRole);
|
|
|
|
numChildren +=
|
|
|
|
(currentRole == nsIAccessibleRole::ROLE_OUTLINEITEM);
|
|
|
|
nsCOMPtr<nsIAccessible> nextGroupChild;
|
|
|
|
groupChild->GetNextSibling(getter_AddRefs(nextGroupChild));
|
|
|
|
groupChild.swap(nextGroupChild);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIAccessible> nextChild;
|
|
|
|
child->GetNextSibling(getter_AddRefs(nextChild));
|
|
|
|
child.swap(nextChild);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (numChildren) {
|
|
|
|
nsTextFormatter::ssprintf(description,
|
|
|
|
NS_LITERAL_STRING("L%d, %d of %d with %d").get(),
|
|
|
|
groupLevel, positionInGroup + 1,
|
|
|
|
similarItemsInGroup + 1, numChildren);
|
|
|
|
} else {
|
|
|
|
nsTextFormatter::ssprintf(description,
|
|
|
|
NS_LITERAL_STRING("L%d, %d of %d").get(),
|
|
|
|
groupLevel, positionInGroup + 1,
|
|
|
|
similarItemsInGroup + 1);
|
|
|
|
}
|
2007-03-27 12:17:11 +00:00
|
|
|
} else { // Position has no level
|
|
|
|
nsTextFormatter::ssprintf(description,
|
|
|
|
NS_LITERAL_STRING("%d of %d").get(),
|
|
|
|
positionInGroup + 1, similarItemsInGroup + 1);
|
2006-12-13 14:40:54 +00:00
|
|
|
}
|
2007-03-27 12:17:11 +00:00
|
|
|
|
|
|
|
*pszDescription = ::SysAllocString(description.get());
|
|
|
|
return S_OK;
|
2006-12-13 14:40:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-07 09:07:24 +00:00
|
|
|
xpAccessible->GetDescription(description);
|
|
|
|
if (!description.IsEmpty()) {
|
|
|
|
// Signal to screen readers that this description is speakable
|
|
|
|
// and is not a formatted positional information description
|
|
|
|
// Don't localize the "Description: " part of this string, it will be
|
|
|
|
// parsed out by assistive technologies.
|
|
|
|
description = NS_LITERAL_STRING("Description: ") + description;
|
2003-04-01 20:02:51 +00:00
|
|
|
}
|
|
|
|
|
2007-04-07 09:07:24 +00:00
|
|
|
*pszDescription = ::SysAllocString(description.get());
|
2003-04-01 20:02:51 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::get_accRole(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [optional][in] */ VARIANT varChild,
|
|
|
|
/* [retval][out] */ VARIANT __RPC_FAR *pvarRole)
|
|
|
|
{
|
|
|
|
VariantInit(pvarRole);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAccessible> xpAccessible;
|
|
|
|
GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
|
|
|
|
|
|
|
|
if (!xpAccessible)
|
|
|
|
return E_FAIL;
|
|
|
|
|
2006-11-08 08:22:46 +00:00
|
|
|
#ifdef DEBUG_A11Y
|
|
|
|
NS_ASSERTION(nsAccessible::IsTextInterfaceSupportCorrect(xpAccessible), "Does not support nsIAccessibleText when it should");
|
|
|
|
#endif
|
|
|
|
|
2006-07-17 14:53:36 +00:00
|
|
|
PRUint32 xpRole = 0, msaaRole = 0;
|
|
|
|
if (NS_FAILED(xpAccessible->GetFinalRole(&xpRole)))
|
2003-04-01 20:02:51 +00:00
|
|
|
return E_FAIL;
|
2007-03-10 03:00:08 +00:00
|
|
|
|
|
|
|
msaaRole = gWindowsRoleMap[xpRole].msaaRole;
|
2007-03-15 02:26:13 +00:00
|
|
|
NS_ASSERTION(gWindowsRoleMap[nsIAccessibleRole::ROLE_LAST_ENTRY].msaaRole == ROLE_WINDOWS_LAST_ENTRY,
|
2006-07-17 14:53:36 +00:00
|
|
|
"MSAA role map skewed");
|
2006-06-16 17:13:37 +00:00
|
|
|
|
2007-02-14 16:48:39 +00:00
|
|
|
// Special case, not a great place for this, but it's better than adding extra role buttonmenu role to ARIA
|
|
|
|
// Other APIs do not have a special role for this.
|
|
|
|
// Really the HASPOPUP state should have been enough for MSAA, but this avoids asking vendors for a fix.
|
2007-03-15 14:18:33 +00:00
|
|
|
if (msaaRole == ROLE_SYSTEM_PUSHBUTTON && (State(xpAccessible) & nsIAccessibleStates::STATE_HASPOPUP)) {
|
2007-02-14 16:48:39 +00:00
|
|
|
msaaRole = ROLE_SYSTEM_BUTTONMENU;
|
|
|
|
}
|
2005-01-21 03:50:26 +00:00
|
|
|
// -- Try enumerated role
|
2006-07-17 14:53:36 +00:00
|
|
|
if (msaaRole != USE_ROLE_STRING) {
|
2005-01-21 03:50:26 +00:00
|
|
|
pvarRole->vt = VT_I4;
|
2006-07-17 14:53:36 +00:00
|
|
|
pvarRole->lVal = msaaRole; // Normal enumerated role
|
2005-01-21 03:50:26 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -- Try BSTR role
|
|
|
|
// Could not map to known enumerated MSAA role like ROLE_BUTTON
|
|
|
|
// Use BSTR role to expose role attribute or tag name + namespace
|
|
|
|
nsCOMPtr<nsIDOMNode> domNode;
|
|
|
|
nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(xpAccessible));
|
2007-03-10 03:00:08 +00:00
|
|
|
if (!accessNode)
|
|
|
|
return E_FAIL;
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
accessNode->GetDOMNode(getter_AddRefs(domNode));
|
2005-06-01 13:54:08 +00:00
|
|
|
nsIContent *content = GetRoleContent(domNode);
|
2007-03-10 03:00:08 +00:00
|
|
|
if (!content)
|
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
if (content->IsNodeOfType(nsINode::eELEMENT)) {
|
2005-01-21 03:50:26 +00:00
|
|
|
nsAutoString roleString;
|
2006-07-17 16:10:22 +00:00
|
|
|
if (msaaRole != ROLE_SYSTEM_CLIENT && !GetRoleAttribute(content, roleString)) {
|
2005-09-24 18:43:15 +00:00
|
|
|
nsINodeInfo *nodeInfo = content->NodeInfo();
|
|
|
|
nodeInfo->GetName(roleString);
|
|
|
|
nsAutoString nameSpaceURI;
|
|
|
|
nodeInfo->GetNamespaceURI(nameSpaceURI);
|
|
|
|
if (!nameSpaceURI.IsEmpty()) {
|
|
|
|
// Only append name space if different from that of current document
|
|
|
|
roleString += NS_LITERAL_STRING(", ") + nameSpaceURI;
|
|
|
|
}
|
2006-02-28 14:35:50 +00:00
|
|
|
}
|
|
|
|
if (!roleString.IsEmpty()) {
|
|
|
|
pvarRole->vt = VT_BSTR;
|
|
|
|
pvarRole->bstrVal = ::SysAllocString(roleString.get());
|
|
|
|
return S_OK;
|
2005-01-21 03:50:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return E_FAIL;
|
2003-04-01 20:02:51 +00:00
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::get_accState(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [optional][in] */ VARIANT varChild,
|
|
|
|
/* [retval][out] */ VARIANT __RPC_FAR *pvarState)
|
|
|
|
{
|
|
|
|
VariantInit(pvarState);
|
|
|
|
pvarState->vt = VT_I4;
|
|
|
|
pvarState->lVal = 0;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAccessible> xpAccessible;
|
|
|
|
GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
|
|
|
|
if (!xpAccessible)
|
|
|
|
return E_FAIL;
|
|
|
|
|
2007-04-02 15:56:24 +00:00
|
|
|
PRUint32 state = 0, extraState;
|
|
|
|
if (NS_FAILED(xpAccessible->GetFinalState(&state, &extraState)))
|
2003-04-01 20:02:51 +00:00
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
pvarState->lVal = state;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::get_accHelp(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [optional][in] */ VARIANT varChild,
|
|
|
|
/* [retval][out] */ BSTR __RPC_FAR *pszHelp)
|
|
|
|
{
|
|
|
|
*pszHelp = NULL;
|
|
|
|
return S_FALSE;
|
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::get_accHelpTopic(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [out] */ BSTR __RPC_FAR *pszHelpFile,
|
|
|
|
/* [optional][in] */ VARIANT varChild,
|
|
|
|
/* [retval][out] */ long __RPC_FAR *pidTopic)
|
|
|
|
{
|
|
|
|
*pszHelpFile = NULL;
|
|
|
|
*pidTopic = 0;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::get_accKeyboardShortcut(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [optional][in] */ VARIANT varChild,
|
|
|
|
/* [retval][out] */ BSTR __RPC_FAR *pszKeyboardShortcut)
|
|
|
|
{
|
|
|
|
*pszKeyboardShortcut = NULL;
|
|
|
|
nsCOMPtr<nsIAccessible> xpAccessible;
|
|
|
|
GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
|
|
|
|
if (xpAccessible) {
|
|
|
|
nsAutoString shortcut;
|
2003-07-31 08:09:39 +00:00
|
|
|
nsresult rv = xpAccessible->GetKeyboardShortcut(shortcut);
|
2003-04-01 20:02:51 +00:00
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return S_FALSE;
|
|
|
|
|
|
|
|
*pszKeyboardShortcut = ::SysAllocString(shortcut.get());
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
return S_FALSE;
|
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::get_accFocus(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [retval][out] */ VARIANT __RPC_FAR *pvarChild)
|
|
|
|
{
|
2005-02-15 14:21:01 +00:00
|
|
|
// VT_EMPTY: None. This object does not have the keyboard focus itself
|
|
|
|
// and does not contain a child that has the keyboard focus.
|
|
|
|
// VT_I4: lVal is CHILDID_SELF. The object itself has the keyboard focus.
|
|
|
|
// VT_I4: lVal contains the child ID of the child element with the keyboard focus.
|
|
|
|
// VT_DISPATCH: pdispVal member is the address of the IDispatch interface
|
|
|
|
// for the child object with the keyboard focus.
|
|
|
|
|
|
|
|
if (!mDOMNode) {
|
|
|
|
return E_FAIL; // This node is shut down
|
|
|
|
}
|
2003-04-01 20:02:51 +00:00
|
|
|
|
2004-07-01 20:43:03 +00:00
|
|
|
VariantInit(pvarChild);
|
2005-02-15 14:21:01 +00:00
|
|
|
|
|
|
|
// Return the current IAccessible child that has focus
|
|
|
|
nsCOMPtr<nsIAccessible> focusedAccessible;
|
2005-02-18 14:36:28 +00:00
|
|
|
GetFocusedChild(getter_AddRefs(focusedAccessible));
|
|
|
|
if (focusedAccessible == this) {
|
|
|
|
pvarChild->vt = VT_I4;
|
|
|
|
pvarChild->lVal = CHILDID_SELF;
|
|
|
|
}
|
|
|
|
else if (focusedAccessible) {
|
|
|
|
pvarChild->vt = VT_DISPATCH;
|
|
|
|
pvarChild->pdispVal = NativeAccessible(focusedAccessible);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pvarChild->vt = VT_EMPTY; // No focus or focus is not a child
|
2005-02-08 15:29:29 +00:00
|
|
|
}
|
|
|
|
|
2004-07-01 20:43:03 +00:00
|
|
|
return S_OK;
|
2003-04-01 20:02:51 +00:00
|
|
|
}
|
|
|
|
|
2007-01-20 12:43:08 +00:00
|
|
|
// This helper class implements IEnumVARIANT for a nsIArray containing nsIAccessible objects.
|
|
|
|
|
|
|
|
class AccessibleEnumerator : public IEnumVARIANT
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
AccessibleEnumerator(nsIArray* aArray) : mArray(aArray), mCurIndex(0) { }
|
|
|
|
AccessibleEnumerator(const AccessibleEnumerator& toCopy) :
|
|
|
|
mArray(toCopy.mArray), mCurIndex(toCopy.mCurIndex) { }
|
|
|
|
~AccessibleEnumerator() { }
|
|
|
|
|
|
|
|
// IUnknown
|
|
|
|
STDMETHODIMP QueryInterface(REFIID iid, void ** ppvObject);
|
|
|
|
STDMETHODIMP_(ULONG) AddRef(void);
|
|
|
|
STDMETHODIMP_(ULONG) Release(void);
|
|
|
|
|
|
|
|
// IEnumVARIANT
|
|
|
|
STDMETHODIMP Next(unsigned long celt, VARIANT FAR* rgvar, unsigned long FAR* pceltFetched);
|
|
|
|
STDMETHODIMP Skip(unsigned long celt);
|
|
|
|
STDMETHODIMP Reset()
|
|
|
|
{
|
|
|
|
mCurIndex = 0;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
STDMETHODIMP Clone(IEnumVARIANT FAR* FAR* ppenum);
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsCOMPtr<nsIArray> mArray;
|
|
|
|
PRUint32 mCurIndex;
|
|
|
|
nsAutoRefCnt mRefCnt;
|
|
|
|
};
|
|
|
|
|
|
|
|
HRESULT
|
|
|
|
AccessibleEnumerator::QueryInterface(REFIID iid, void ** ppvObject)
|
|
|
|
{
|
|
|
|
if (iid == IID_IEnumVARIANT) {
|
|
|
|
*ppvObject = static_cast<IEnumVARIANT*>(this);
|
|
|
|
AddRef();
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
if (iid == IID_IUnknown) {
|
|
|
|
*ppvObject = static_cast<IUnknown*>(this);
|
|
|
|
AddRef();
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ppvObject = NULL;
|
|
|
|
return E_NOINTERFACE;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
|
|
AccessibleEnumerator::AddRef(void)
|
|
|
|
{
|
|
|
|
return ++mRefCnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
|
|
AccessibleEnumerator::Release(void)
|
|
|
|
{
|
|
|
|
ULONG r = --mRefCnt;
|
|
|
|
if (r == 0)
|
|
|
|
delete this;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
AccessibleEnumerator::Next(unsigned long celt, VARIANT FAR* rgvar, unsigned long FAR* pceltFetched)
|
|
|
|
{
|
|
|
|
PRUint32 length = 0;
|
|
|
|
mArray->GetLength(&length);
|
|
|
|
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
|
|
// Can't get more elements than there are...
|
|
|
|
if (celt > length - mCurIndex) {
|
|
|
|
hr = S_FALSE;
|
|
|
|
celt = length - mCurIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (PRUint32 i = 0; i < celt; ++i, ++mCurIndex) {
|
|
|
|
// Copy the elements of the array into rgvar
|
|
|
|
nsCOMPtr<nsIAccessible> accel(do_QueryElementAt(mArray, mCurIndex));
|
|
|
|
NS_ASSERTION(accel, "Invalid pointer in mArray");
|
|
|
|
|
|
|
|
if (accel) {
|
|
|
|
rgvar[i].vt = VT_DISPATCH;
|
|
|
|
rgvar[i].pdispVal = nsAccessibleWrap::NativeAccessible(accel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pceltFetched)
|
|
|
|
*pceltFetched = celt;
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
AccessibleEnumerator::Clone(IEnumVARIANT FAR* FAR* ppenum)
|
|
|
|
{
|
|
|
|
*ppenum = new AccessibleEnumerator(*this);
|
|
|
|
if (!*ppenum)
|
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
NS_ADDREF(*ppenum);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
AccessibleEnumerator::Skip(unsigned long celt)
|
|
|
|
{
|
|
|
|
PRUint32 length = 0;
|
|
|
|
mArray->GetLength(&length);
|
|
|
|
// Check if we can skip the requested number of elements
|
|
|
|
if (celt > length - mCurIndex) {
|
|
|
|
mCurIndex = length;
|
|
|
|
return S_FALSE;
|
|
|
|
}
|
|
|
|
mCurIndex += celt;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2003-04-01 20:02:51 +00:00
|
|
|
/**
|
|
|
|
* This method is called when a client wants to know which children of a node
|
2007-01-20 12:43:08 +00:00
|
|
|
* are selected. Note that this method can only find selected children for
|
|
|
|
* nsIAccessible object which implement nsIAccessibleSelectable.
|
2003-04-01 20:02:51 +00:00
|
|
|
*
|
|
|
|
* The VARIANT return value arguement is expected to either contain a single IAccessible
|
|
|
|
* or an IEnumVARIANT of IAccessibles. We return the IEnumVARIANT regardless of the number
|
2007-01-20 12:43:08 +00:00
|
|
|
* of children selected, unless there are none selected in which case we return an empty
|
2003-04-01 20:02:51 +00:00
|
|
|
* VARIANT.
|
|
|
|
*
|
2007-01-20 12:43:08 +00:00
|
|
|
* We get the selected options from the select's accessible object and wrap
|
|
|
|
* those in an AccessibleEnumerator which we then put in the return VARIANT.
|
2003-04-01 20:02:51 +00:00
|
|
|
*
|
|
|
|
* returns a VT_EMPTY VARIANT if:
|
2007-01-20 12:43:08 +00:00
|
|
|
* - there are no selected children for this object
|
|
|
|
* - the object is not the type that can have children selected
|
2003-04-01 20:02:51 +00:00
|
|
|
*/
|
|
|
|
STDMETHODIMP nsAccessibleWrap::get_accSelection(VARIANT __RPC_FAR *pvarChildren)
|
|
|
|
{
|
|
|
|
VariantInit(pvarChildren);
|
|
|
|
pvarChildren->vt = VT_EMPTY;
|
|
|
|
|
2007-01-20 12:43:08 +00:00
|
|
|
nsCOMPtr<nsIAccessibleSelectable>
|
|
|
|
select(do_QueryInterface(NS_STATIC_CAST(nsIAccessible*, this)));
|
2003-04-01 20:02:51 +00:00
|
|
|
|
|
|
|
if (select) { // do we have an nsIAccessibleSelectable?
|
|
|
|
// we have an accessible that can have children selected
|
2003-07-22 14:55:22 +00:00
|
|
|
nsCOMPtr<nsIArray> selectedOptions;
|
2003-04-01 20:02:51 +00:00
|
|
|
// gets the selected options as nsIAccessibles.
|
|
|
|
select->GetSelectedChildren(getter_AddRefs(selectedOptions));
|
|
|
|
if (selectedOptions) { // false if the select has no children or none are selected
|
2007-01-20 12:43:08 +00:00
|
|
|
// 1) Create and initialize the enumeration
|
|
|
|
nsRefPtr<AccessibleEnumerator> pEnum = new AccessibleEnumerator(selectedOptions);
|
2003-04-01 20:02:51 +00:00
|
|
|
|
2007-01-20 12:43:08 +00:00
|
|
|
// 2) Put the enumerator in the VARIANT
|
|
|
|
if (!pEnum)
|
|
|
|
return E_OUTOFMEMORY;
|
2003-04-01 20:02:51 +00:00
|
|
|
pvarChildren->vt = VT_UNKNOWN; // this must be VT_UNKNOWN for an IEnumVARIANT
|
2007-01-20 12:43:08 +00:00
|
|
|
NS_ADDREF(pvarChildren->punkVal = pEnum);
|
2003-04-01 20:02:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::get_accDefaultAction(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [optional][in] */ VARIANT varChild,
|
|
|
|
/* [retval][out] */ BSTR __RPC_FAR *pszDefaultAction)
|
|
|
|
{
|
|
|
|
*pszDefaultAction = NULL;
|
|
|
|
nsCOMPtr<nsIAccessible> xpAccessible;
|
|
|
|
GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
|
|
|
|
if (xpAccessible) {
|
|
|
|
nsAutoString defaultAction;
|
2003-07-31 08:09:39 +00:00
|
|
|
if (NS_FAILED(xpAccessible->GetActionName(0, defaultAction)))
|
2003-04-01 20:02:51 +00:00
|
|
|
return S_FALSE;
|
|
|
|
|
|
|
|
*pszDefaultAction = ::SysAllocString(defaultAction.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::accSelect(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [in] */ long flagsSelect,
|
|
|
|
/* [optional][in] */ VARIANT varChild)
|
|
|
|
{
|
|
|
|
// currently only handle focus and selection
|
|
|
|
nsCOMPtr<nsIAccessible> xpAccessible;
|
|
|
|
GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
|
|
|
|
|
|
|
|
if (flagsSelect & (SELFLAG_TAKEFOCUS|SELFLAG_TAKESELECTION|SELFLAG_REMOVESELECTION))
|
|
|
|
{
|
|
|
|
if (flagsSelect & SELFLAG_TAKEFOCUS)
|
2003-07-31 08:09:39 +00:00
|
|
|
xpAccessible->TakeFocus();
|
2003-04-01 20:02:51 +00:00
|
|
|
|
|
|
|
if (flagsSelect & SELFLAG_TAKESELECTION)
|
2003-07-31 08:09:39 +00:00
|
|
|
xpAccessible->TakeSelection();
|
2003-04-01 20:02:51 +00:00
|
|
|
|
2006-06-15 18:29:44 +00:00
|
|
|
if (flagsSelect & SELFLAG_ADDSELECTION)
|
|
|
|
xpAccessible->SetSelected(PR_TRUE);
|
|
|
|
|
2003-04-01 20:02:51 +00:00
|
|
|
if (flagsSelect & SELFLAG_REMOVESELECTION)
|
2006-06-15 18:29:44 +00:00
|
|
|
xpAccessible->SetSelected(PR_FALSE);
|
|
|
|
|
|
|
|
if (flagsSelect & SELFLAG_EXTENDSELECTION)
|
|
|
|
xpAccessible->ExtendSelection();
|
2003-04-01 20:02:51 +00:00
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::accLocation(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [out] */ long __RPC_FAR *pxLeft,
|
|
|
|
/* [out] */ long __RPC_FAR *pyTop,
|
|
|
|
/* [out] */ long __RPC_FAR *pcxWidth,
|
|
|
|
/* [out] */ long __RPC_FAR *pcyHeight,
|
|
|
|
/* [optional][in] */ VARIANT varChild)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAccessible> xpAccessible;
|
|
|
|
GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
|
|
|
|
|
|
|
|
if (xpAccessible) {
|
|
|
|
PRInt32 x, y, width, height;
|
2003-07-31 08:09:39 +00:00
|
|
|
if (NS_FAILED(xpAccessible->GetBounds(&x, &y, &width, &height)))
|
2003-04-01 20:02:51 +00:00
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
*pxLeft = x;
|
|
|
|
*pyTop = y;
|
|
|
|
*pcxWidth = width;
|
|
|
|
*pcyHeight = height;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
return E_FAIL;
|
2003-04-01 20:02:51 +00:00
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::accNavigate(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [in] */ long navDir,
|
|
|
|
/* [optional][in] */ VARIANT varStart,
|
|
|
|
/* [retval][out] */ VARIANT __RPC_FAR *pvarEndUpAt)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAccessible> xpAccessibleStart, xpAccessibleResult;
|
|
|
|
GetXPAccessibleFor(varStart, getter_AddRefs(xpAccessibleStart));
|
2003-04-15 08:45:55 +00:00
|
|
|
if (!xpAccessibleStart)
|
|
|
|
return E_FAIL;
|
2003-04-01 20:02:51 +00:00
|
|
|
|
|
|
|
VariantInit(pvarEndUpAt);
|
2005-06-24 16:29:15 +00:00
|
|
|
PRUint32 xpRelation = 0;
|
2003-04-01 20:02:51 +00:00
|
|
|
|
|
|
|
switch(navDir) {
|
2006-02-28 14:35:50 +00:00
|
|
|
case NAVDIR_DOWN:
|
2003-07-31 08:09:39 +00:00
|
|
|
xpAccessibleStart->GetAccessibleBelow(getter_AddRefs(xpAccessibleResult));
|
2003-04-01 20:02:51 +00:00
|
|
|
break;
|
|
|
|
case NAVDIR_FIRSTCHILD:
|
2006-07-12 13:14:53 +00:00
|
|
|
if (!MustPrune(xpAccessibleStart)) {
|
|
|
|
xpAccessibleStart->GetFirstChild(getter_AddRefs(xpAccessibleResult));
|
|
|
|
}
|
2003-04-01 20:02:51 +00:00
|
|
|
break;
|
|
|
|
case NAVDIR_LASTCHILD:
|
2006-07-12 13:14:53 +00:00
|
|
|
if (!MustPrune(xpAccessibleStart)) {
|
|
|
|
xpAccessibleStart->GetLastChild(getter_AddRefs(xpAccessibleResult));
|
|
|
|
}
|
2003-04-01 20:02:51 +00:00
|
|
|
break;
|
|
|
|
case NAVDIR_LEFT:
|
2003-07-31 08:09:39 +00:00
|
|
|
xpAccessibleStart->GetAccessibleToLeft(getter_AddRefs(xpAccessibleResult));
|
2003-04-01 20:02:51 +00:00
|
|
|
break;
|
|
|
|
case NAVDIR_NEXT:
|
2003-07-31 08:09:39 +00:00
|
|
|
xpAccessibleStart->GetNextSibling(getter_AddRefs(xpAccessibleResult));
|
2003-04-01 20:02:51 +00:00
|
|
|
break;
|
|
|
|
case NAVDIR_PREVIOUS:
|
2003-07-31 08:09:39 +00:00
|
|
|
xpAccessibleStart->GetPreviousSibling(getter_AddRefs(xpAccessibleResult));
|
2003-04-01 20:02:51 +00:00
|
|
|
break;
|
|
|
|
case NAVDIR_RIGHT:
|
2003-07-31 08:09:39 +00:00
|
|
|
xpAccessibleStart->GetAccessibleToRight(getter_AddRefs(xpAccessibleResult));
|
2003-04-01 20:02:51 +00:00
|
|
|
break;
|
|
|
|
case NAVDIR_UP:
|
2003-07-31 08:09:39 +00:00
|
|
|
xpAccessibleStart->GetAccessibleAbove(getter_AddRefs(xpAccessibleResult));
|
2003-04-01 20:02:51 +00:00
|
|
|
break;
|
2005-06-24 16:29:15 +00:00
|
|
|
// MSAA relationship extensions to accNavigate
|
|
|
|
case NAVRELATION_CONTROLLED_BY: xpRelation = RELATION_CONTROLLED_BY; break;
|
|
|
|
case NAVRELATION_CONTROLLER_FOR: xpRelation = RELATION_CONTROLLER_FOR; break;
|
|
|
|
case NAVRELATION_LABEL_FOR: xpRelation = RELATION_LABEL_FOR; break;
|
|
|
|
case NAVRELATION_LABELLED_BY: xpRelation = RELATION_LABELLED_BY; break;
|
|
|
|
case NAVRELATION_MEMBER_OF: xpRelation = RELATION_MEMBER_OF; break;
|
|
|
|
case NAVRELATION_NODE_CHILD_OF: xpRelation = RELATION_NODE_CHILD_OF; break;
|
|
|
|
case NAVRELATION_FLOWS_TO: xpRelation = RELATION_FLOWS_TO; break;
|
|
|
|
case NAVRELATION_FLOWS_FROM: xpRelation = RELATION_FLOWS_FROM; break;
|
|
|
|
case NAVRELATION_SUBWINDOW_OF: xpRelation = RELATION_SUBWINDOW_OF; break;
|
|
|
|
case NAVRELATION_EMBEDS: xpRelation = RELATION_EMBEDS; break;
|
|
|
|
case NAVRELATION_EMBEDDED_BY: xpRelation = RELATION_EMBEDDED_BY; break;
|
|
|
|
case NAVRELATION_POPUP_FOR: xpRelation = RELATION_POPUP_FOR; break;
|
|
|
|
case NAVRELATION_PARENT_WINDOW_OF: xpRelation = RELATION_PARENT_WINDOW_OF; break;
|
|
|
|
case NAVRELATION_DEFAULT_BUTTON: xpRelation = RELATION_DEFAULT_BUTTON; break;
|
|
|
|
case NAVRELATION_DESCRIBED_BY: xpRelation = RELATION_DESCRIBED_BY; break;
|
|
|
|
case NAVRELATION_DESCRIPTION_FOR: xpRelation = RELATION_DESCRIPTION_FOR; break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pvarEndUpAt->vt = VT_EMPTY;
|
|
|
|
|
|
|
|
if (xpRelation) {
|
|
|
|
nsresult rv = GetAccessibleRelated(xpRelation,
|
|
|
|
getter_AddRefs(xpAccessibleResult));
|
|
|
|
if (rv == NS_ERROR_NOT_IMPLEMENTED) {
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
2003-04-01 20:02:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (xpAccessibleResult) {
|
|
|
|
pvarEndUpAt->pdispVal = NativeAccessible(xpAccessibleResult);
|
|
|
|
pvarEndUpAt->vt = VT_DISPATCH;
|
|
|
|
return NS_OK;
|
2006-02-28 14:35:50 +00:00
|
|
|
}
|
2003-04-01 20:02:51 +00:00
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::accHitTest(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [in] */ long xLeft,
|
|
|
|
/* [in] */ long yTop,
|
|
|
|
/* [retval][out] */ VARIANT __RPC_FAR *pvarChild)
|
|
|
|
{
|
|
|
|
VariantInit(pvarChild);
|
|
|
|
|
|
|
|
// convert to window coords
|
|
|
|
nsCOMPtr<nsIAccessible> xpAccessible;
|
|
|
|
|
|
|
|
xLeft = xLeft;
|
|
|
|
yTop = yTop;
|
|
|
|
|
2006-07-12 13:14:53 +00:00
|
|
|
if (MustPrune(this)) {
|
|
|
|
xpAccessible = this;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
GetChildAtPoint(xLeft, yTop, getter_AddRefs(xpAccessible));
|
|
|
|
}
|
2003-04-01 20:02:51 +00:00
|
|
|
|
|
|
|
// if we got a child
|
|
|
|
if (xpAccessible) {
|
|
|
|
// if the child is us
|
|
|
|
if (xpAccessible == NS_STATIC_CAST(nsIAccessible*, this)) {
|
|
|
|
pvarChild->vt = VT_I4;
|
|
|
|
pvarChild->lVal = CHILDID_SELF;
|
|
|
|
} else { // its not create an Accessible for it.
|
|
|
|
pvarChild->vt = VT_DISPATCH;
|
|
|
|
pvarChild->pdispVal = NativeAccessible(xpAccessible);
|
2004-07-16 16:37:28 +00:00
|
|
|
nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(xpAccessible));
|
|
|
|
NS_ASSERTION(accessNode, "Unable to QI to nsIAccessNode");
|
2003-05-01 10:25:45 +00:00
|
|
|
nsCOMPtr<nsIDOMNode> domNode;
|
2004-07-16 16:37:28 +00:00
|
|
|
accessNode->GetDOMNode(getter_AddRefs(domNode));
|
2003-05-01 10:25:45 +00:00
|
|
|
if (!domNode) {
|
|
|
|
// Has already been shut down
|
|
|
|
pvarChild->vt = VT_EMPTY;
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
2003-04-01 20:02:51 +00:00
|
|
|
}
|
|
|
|
} else {
|
2003-04-15 08:45:55 +00:00
|
|
|
// no child at that point
|
|
|
|
pvarChild->vt = VT_EMPTY;
|
|
|
|
return E_FAIL;
|
2003-04-01 20:02:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::accDoDefaultAction(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [optional][in] */ VARIANT varChild)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAccessible> xpAccessible;
|
|
|
|
GetXPAccessibleFor(varChild, getter_AddRefs(xpAccessible));
|
|
|
|
|
2003-07-31 08:09:39 +00:00
|
|
|
if (!xpAccessible || FAILED(xpAccessible->DoAction(0))) {
|
2003-04-01 20:02:51 +00:00
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::put_accName(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [optional][in] */ VARIANT varChild,
|
|
|
|
/* [in] */ BSTR szName)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP nsAccessibleWrap::put_accValue(
|
2003-04-01 20:02:51 +00:00
|
|
|
/* [optional][in] */ VARIANT varChild,
|
|
|
|
/* [in] */ BSTR szValue)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "mshtml.h"
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::QueryService(REFGUID guidService, REFIID iid, void** ppv)
|
|
|
|
{
|
2004-06-22 16:38:27 +00:00
|
|
|
/**
|
|
|
|
* To get an ISimpleDOMNode, ISimpleDOMDocument or ISimpleDOMText
|
|
|
|
* from an IAccessible you have to use IServiceProvider like this:
|
|
|
|
* --------------------------------------------------------------
|
|
|
|
* ISimpleDOMDocument *pAccDoc = NULL;
|
|
|
|
* IServiceProvider *pServProv = NULL;
|
|
|
|
* pAcc->QueryInterface(IID_IServiceProvider, (void**)&pServProv);
|
|
|
|
* if (pServProv) {
|
|
|
|
* const GUID unused;
|
|
|
|
* pServProv->QueryService(unused, IID_ISimpleDOMDocument, (void**)&pAccDoc);
|
|
|
|
* pServProv->Release();
|
|
|
|
* }
|
|
|
|
*/
|
|
|
|
|
|
|
|
return QueryInterface(iid, ppv);
|
2003-04-01 20:02:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::Next(ULONG aNumElementsRequested, VARIANT FAR* pvar, ULONG FAR* aNumElementsFetched)
|
|
|
|
{
|
2003-04-15 08:45:55 +00:00
|
|
|
// If there are two clients using this at the same time, and they are
|
|
|
|
// each using a different mEnumVariant position it would be bad, because
|
|
|
|
// we have only 1 object and can only keep of mEnumVARIANT position once
|
|
|
|
|
|
|
|
// Children already cached via QI to IEnumVARIANT
|
2003-04-01 20:02:51 +00:00
|
|
|
*aNumElementsFetched = 0;
|
|
|
|
|
2003-04-15 08:45:55 +00:00
|
|
|
PRInt32 numChildren;
|
2003-07-31 08:09:39 +00:00
|
|
|
GetChildCount(&numChildren);
|
2003-04-15 08:45:55 +00:00
|
|
|
|
2003-04-01 20:02:51 +00:00
|
|
|
if (aNumElementsRequested <= 0 || !pvar ||
|
2003-04-15 08:45:55 +00:00
|
|
|
mEnumVARIANTPosition >= numChildren) {
|
2003-04-01 20:02:51 +00:00
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
VARIANT varStart;
|
|
|
|
VariantInit(&varStart);
|
|
|
|
varStart.lVal = CHILDID_SELF;
|
|
|
|
varStart.vt = VT_I4;
|
|
|
|
|
|
|
|
accNavigate(NAVDIR_FIRSTCHILD, varStart, &pvar[0]);
|
|
|
|
|
|
|
|
for (long childIndex = 0; pvar[*aNumElementsFetched].vt == VT_DISPATCH; ++childIndex) {
|
|
|
|
PRBool wasAccessibleFetched = PR_FALSE;
|
2006-02-28 14:35:50 +00:00
|
|
|
nsAccessibleWrap *msaaAccessible =
|
2003-04-01 20:02:51 +00:00
|
|
|
NS_STATIC_CAST(nsAccessibleWrap*, pvar[*aNumElementsFetched].pdispVal);
|
2005-09-02 01:33:23 +00:00
|
|
|
if (!msaaAccessible)
|
|
|
|
break;
|
2003-04-01 20:02:51 +00:00
|
|
|
if (childIndex >= mEnumVARIANTPosition) {
|
|
|
|
if (++*aNumElementsFetched >= aNumElementsRequested)
|
|
|
|
break;
|
|
|
|
wasAccessibleFetched = PR_TRUE;
|
|
|
|
}
|
|
|
|
msaaAccessible->accNavigate(NAVDIR_NEXT, varStart, &pvar[*aNumElementsFetched] );
|
|
|
|
if (!wasAccessibleFetched)
|
|
|
|
msaaAccessible->nsAccessNode::Release(); // this accessible will not be received by the caller
|
|
|
|
}
|
|
|
|
|
2004-06-04 19:28:36 +00:00
|
|
|
mEnumVARIANTPosition += NS_STATIC_CAST(PRUint16, *aNumElementsFetched);
|
2003-04-01 20:02:51 +00:00
|
|
|
return NOERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::Skip(ULONG aNumElements)
|
|
|
|
{
|
2004-06-04 19:28:36 +00:00
|
|
|
mEnumVARIANTPosition += NS_STATIC_CAST(PRUint16, aNumElements);
|
2003-04-01 20:02:51 +00:00
|
|
|
|
2003-04-15 08:45:55 +00:00
|
|
|
PRInt32 numChildren;
|
2003-07-31 08:09:39 +00:00
|
|
|
GetChildCount(&numChildren);
|
2006-02-28 14:35:50 +00:00
|
|
|
|
2003-04-15 08:45:55 +00:00
|
|
|
if (mEnumVARIANTPosition > numChildren)
|
2003-04-01 20:02:51 +00:00
|
|
|
{
|
2003-04-15 08:45:55 +00:00
|
|
|
mEnumVARIANTPosition = numChildren;
|
2003-04-01 20:02:51 +00:00
|
|
|
return S_FALSE;
|
|
|
|
}
|
|
|
|
return NOERROR;
|
|
|
|
}
|
|
|
|
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP
|
2003-04-01 20:02:51 +00:00
|
|
|
nsAccessibleWrap::Reset(void)
|
|
|
|
{
|
|
|
|
mEnumVARIANTPosition = 0;
|
|
|
|
return NOERROR;
|
|
|
|
}
|
|
|
|
|
2007-03-09 13:51:47 +00:00
|
|
|
|
|
|
|
// IAccessible2
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_nRelations(long *nRelations)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_relation(long relationIndex,
|
|
|
|
IAccessibleRelation **relation)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_relations(long maxRelations,
|
|
|
|
IAccessibleRelation **relation,
|
|
|
|
long *nRelations)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::role(long *role)
|
|
|
|
{
|
2007-03-10 03:00:08 +00:00
|
|
|
PRUint32 xpRole = 0;
|
|
|
|
if (NS_FAILED(GetFinalRole(&xpRole)))
|
|
|
|
return E_FAIL;
|
|
|
|
|
2007-03-15 02:26:13 +00:00
|
|
|
NS_ASSERTION(gWindowsRoleMap[nsIAccessibleRole::ROLE_LAST_ENTRY].ia2Role == ROLE_WINDOWS_LAST_ENTRY,
|
2007-03-10 03:00:08 +00:00
|
|
|
"MSAA role map skewed");
|
|
|
|
|
|
|
|
*role = gWindowsRoleMap[xpRole].ia2Role;
|
|
|
|
|
|
|
|
return S_OK;
|
2007-03-09 13:51:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
2007-04-12 16:54:09 +00:00
|
|
|
nsAccessibleWrap::scrollTo(enum IA2ScrollType aScrollType)
|
2007-03-09 13:51:47 +00:00
|
|
|
{
|
2007-04-12 16:54:09 +00:00
|
|
|
if (NS_SUCCEEDED(ScrollTo(aScrollType)))
|
2007-03-09 13:51:47 +00:00
|
|
|
return S_OK;
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
2007-04-08 03:58:08 +00:00
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::scrollToPoint(enum IA2CoordinateType coordinateType,
|
|
|
|
long x, long y)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2007-03-09 13:51:47 +00:00
|
|
|
STDMETHODIMP
|
2007-03-27 12:17:11 +00:00
|
|
|
nsAccessibleWrap::get_groupPosition(long *aGroupLevel,
|
|
|
|
long *aSimilarItemsInGroup,
|
|
|
|
long *aPositionInGroup)
|
2007-03-09 13:51:47 +00:00
|
|
|
{
|
2007-03-27 12:17:11 +00:00
|
|
|
PRInt32 groupLevel = 0;
|
|
|
|
PRInt32 similarItemsInGroup = 0;
|
|
|
|
PRInt32 positionInGroup = 0;
|
|
|
|
nsresult rv = GroupPosition(&groupLevel, &similarItemsInGroup,
|
|
|
|
&positionInGroup);
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
*aGroupLevel = groupLevel;
|
|
|
|
*aSimilarItemsInGroup = similarItemsInGroup;
|
|
|
|
*aPositionInGroup = positionInGroup;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return E_FAIL;
|
2007-03-09 13:51:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
2007-03-18 15:54:48 +00:00
|
|
|
nsAccessibleWrap::get_states(AccessibleStates *aStates)
|
2007-03-09 13:51:47 +00:00
|
|
|
{
|
2007-03-18 15:54:48 +00:00
|
|
|
*aStates = 0;
|
|
|
|
|
|
|
|
// XXX: bug 344674 should come with better approach that we have here.
|
|
|
|
|
2007-04-02 15:56:24 +00:00
|
|
|
PRUint32 states = 0, extraStates = 0;
|
|
|
|
nsresult rv = GetFinalState(&states, &extraStates);
|
2007-03-18 15:54:48 +00:00
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
if (states & nsIAccessibleStates::STATE_INVALID)
|
|
|
|
*aStates |= IA2_STATE_INVALID_ENTRY;
|
|
|
|
else if (states & nsIAccessibleStates::STATE_REQUIRED)
|
|
|
|
*aStates |= IA2_STATE_REQUIRED;
|
|
|
|
|
|
|
|
// The following IA2 states are not supported by Gecko
|
|
|
|
// IA2_STATE_ARMED
|
|
|
|
// IA2_STATE_MANAGES_DESCENDAN
|
|
|
|
// IA2_STATE_ICONIFIED
|
|
|
|
// IA2_STATE_INVALID
|
|
|
|
|
2007-04-02 15:56:24 +00:00
|
|
|
if (extraStates & nsIAccessibleStates::EXT_STATE_ACTIVE)
|
2007-03-18 15:54:48 +00:00
|
|
|
*aStates |= IA2_STATE_ACTIVE;
|
2007-04-02 15:56:24 +00:00
|
|
|
else if (extraStates & nsIAccessibleStates::EXT_STATE_DEFUNCT)
|
2007-03-18 15:54:48 +00:00
|
|
|
*aStates |= IA2_STATE_DEFUNCT;
|
2007-04-02 15:56:24 +00:00
|
|
|
else if (extraStates & nsIAccessibleStates::EXT_STATE_EDITABLE)
|
2007-03-18 15:54:48 +00:00
|
|
|
*aStates |= IA2_STATE_EDITABLE;
|
2007-04-02 15:56:24 +00:00
|
|
|
else if (extraStates & nsIAccessibleStates::EXT_STATE_HORIZONTAL)
|
2007-03-18 15:54:48 +00:00
|
|
|
*aStates |= IA2_STATE_HORIZONTAL;
|
2007-04-02 15:56:24 +00:00
|
|
|
else if (extraStates & nsIAccessibleStates::EXT_STATE_MODAL)
|
2007-03-18 15:54:48 +00:00
|
|
|
*aStates |= IA2_STATE_MODAL;
|
2007-04-02 15:56:24 +00:00
|
|
|
else if (extraStates & nsIAccessibleStates::EXT_STATE_MULTI_LINE)
|
2007-03-18 15:54:48 +00:00
|
|
|
*aStates |= IA2_STATE_MULTI_LINE;
|
2007-04-02 15:56:24 +00:00
|
|
|
else if (extraStates & nsIAccessibleStates::EXT_STATE_OPAQUE)
|
2007-03-18 15:54:48 +00:00
|
|
|
*aStates |= IA2_STATE_OPAQUE;
|
2007-04-02 15:56:24 +00:00
|
|
|
else if (extraStates & nsIAccessibleStates::EXT_STATE_SELECTABLE_TEXT)
|
2007-03-18 15:54:48 +00:00
|
|
|
*aStates |= IA2_STATE_SELECTABLE_TEXT;
|
2007-04-02 15:56:24 +00:00
|
|
|
else if (extraStates & nsIAccessibleStates::EXT_STATE_SINGLE_LINE)
|
2007-03-18 15:54:48 +00:00
|
|
|
*aStates |= IA2_STATE_SINGLE_LINE;
|
2007-04-02 15:56:24 +00:00
|
|
|
else if (extraStates & nsIAccessibleStates::EXT_STATE_STALE)
|
2007-03-18 15:54:48 +00:00
|
|
|
*aStates |= IA2_STATE_STALE;
|
2007-04-02 15:56:24 +00:00
|
|
|
else if (extraStates & nsIAccessibleStates::EXT_STATE_SUPPORTS_AUTOCOMPLETION)
|
2007-03-18 15:54:48 +00:00
|
|
|
*aStates |= IA2_STATE_SUPPORTS_AUTOCOMPLETION;
|
2007-04-02 15:56:24 +00:00
|
|
|
else if (extraStates & nsIAccessibleStates::EXT_STATE_TRANSIENT)
|
2007-03-18 15:54:48 +00:00
|
|
|
*aStates |= IA2_STATE_TRANSIENT;
|
2007-04-02 15:56:24 +00:00
|
|
|
else if (extraStates & nsIAccessibleStates::EXT_STATE_VERTICAL)
|
2007-03-18 15:54:48 +00:00
|
|
|
*aStates |= IA2_STATE_VERTICAL;
|
|
|
|
|
|
|
|
return S_OK;
|
2007-03-09 13:51:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_extendedRole(BSTR *extendedRole)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_localizedExtendedRole(BSTR *localizedExtendedRole)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_nExtendedStates(long *nExtendedStates)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_extendedStates(long maxExtendedStates,
|
|
|
|
BSTR **extendedStates,
|
|
|
|
long *nExtendedStates)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_localizedExtendedStates(long maxLocalizedExtendedStates,
|
|
|
|
BSTR **localizedExtendedStates,
|
|
|
|
long *nLocalizedExtendedStates)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_uniqueID(long *uniqueID)
|
|
|
|
{
|
2007-04-08 03:58:08 +00:00
|
|
|
void *id;
|
|
|
|
if (NS_SUCCEEDED(GetUniqueID(&id))) {
|
|
|
|
*uniqueID = NS_REINTERPRET_POINTER_CAST(long, id);
|
2007-03-09 13:51:47 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
2007-03-09 16:03:00 +00:00
|
|
|
nsAccessibleWrap::get_windowHandle(HWND *windowHandle)
|
2007-03-09 13:51:47 +00:00
|
|
|
{
|
|
|
|
void **handle = nsnull;
|
|
|
|
if (NS_SUCCEEDED(GetOwnerWindow(handle))) {
|
2007-03-09 16:03:00 +00:00
|
|
|
*windowHandle = NS_REINTERPRET_POINTER_CAST(HWND, *handle);
|
2007-03-09 13:51:47 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_indexInParent(long *indexInParent)
|
|
|
|
{
|
|
|
|
PRInt32 index;
|
|
|
|
if (NS_SUCCEEDED(GetIndexInParent(&index))) {
|
|
|
|
*indexInParent = index;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_locale(IA2Locale *locale)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_attributes(BSTR *attributes)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-18 05:21:13 +00:00
|
|
|
// IAccessibleAction
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::nActions(long *aNumActions)
|
|
|
|
{
|
|
|
|
PRUint8 count = 0;
|
|
|
|
nsresult rv = GetNumActions(&count);
|
|
|
|
*aNumActions = count;
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
|
|
return NS_OK;
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::doAction(long aActionIndex)
|
|
|
|
{
|
|
|
|
PRUint8 index = NS_STATIC_CAST(PRUint8, aActionIndex);
|
|
|
|
if (NS_SUCCEEDED(DoAction(index)))
|
|
|
|
return S_OK;
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_description(long aActionIndex, BSTR *aDescription)
|
|
|
|
{
|
|
|
|
*aDescription = NULL;
|
|
|
|
|
|
|
|
nsAutoString description;
|
|
|
|
PRUint8 index = NS_STATIC_CAST(PRUint8, aActionIndex);
|
|
|
|
if (NS_FAILED(GetActionDescription(index, description)))
|
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
if (!description.IsVoid())
|
|
|
|
*aDescription = ::SysAllocString(description.get());
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_keyBinding(long aActionIndex, long aNumMaxBinding,
|
|
|
|
BSTR **aKeyBinding,
|
|
|
|
long *aNumBinding)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMDOMStringList> keys;
|
|
|
|
PRUint8 index = NS_STATIC_CAST(PRUint8, aActionIndex);
|
|
|
|
nsresult rv = GetKeyBindings(index, getter_AddRefs(keys));
|
|
|
|
if (NS_FAILED(rv))
|
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
PRUint32 length = 0;
|
|
|
|
keys->GetLength(&length);
|
|
|
|
|
|
|
|
PRBool aUseNumMaxBinding = length > NS_STATIC_CAST(PRUint32, aNumMaxBinding);
|
|
|
|
|
|
|
|
PRUint32 maxBinding = NS_STATIC_CAST(PRUint32, aNumMaxBinding);
|
|
|
|
|
|
|
|
PRUint32 numBinding = length > maxBinding ? maxBinding : length;
|
|
|
|
*aNumBinding = numBinding;
|
|
|
|
|
|
|
|
*aKeyBinding = new BSTR[numBinding];
|
|
|
|
if (!*aKeyBinding)
|
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
|
|
|
for (PRUint32 i = 0; i < numBinding; i++) {
|
|
|
|
nsAutoString key;
|
|
|
|
keys->Item(i, key);
|
|
|
|
*aKeyBinding[i] = ::SysAllocString(key.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_name(long aActionIndex, BSTR *aName)
|
|
|
|
{
|
|
|
|
*aName = NULL;
|
|
|
|
|
|
|
|
nsAutoString name;
|
|
|
|
PRUint8 index = NS_STATIC_CAST(PRUint8, aActionIndex);
|
|
|
|
if (NS_FAILED(GetActionName(index, name)))
|
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
if (!name.IsVoid())
|
|
|
|
*aName = ::SysAllocString(name.get());
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::get_localizedName(long aActionIndex, BSTR *aLocalizedName)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-04-01 20:02:51 +00:00
|
|
|
STDMETHODIMP
|
|
|
|
nsAccessibleWrap::Clone(IEnumVARIANT FAR* FAR* ppenum)
|
|
|
|
{
|
|
|
|
// Clone could be bad, the cloned items aren't tracked for shutdown
|
|
|
|
// Then again, as long as the client releases the items in time, we're okay
|
|
|
|
*ppenum = nsnull;
|
|
|
|
|
2003-04-15 08:45:55 +00:00
|
|
|
nsAccessibleWrap *accessibleWrap = new nsAccessibleWrap(mDOMNode, mWeakShell);
|
2003-04-01 20:02:51 +00:00
|
|
|
if (!accessibleWrap)
|
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
IAccessible *msaaAccessible = NS_STATIC_CAST(IAccessible*, accessibleWrap);
|
|
|
|
msaaAccessible->AddRef();
|
|
|
|
QueryInterface(IID_IEnumVARIANT, (void**)ppenum);
|
|
|
|
if (*ppenum)
|
|
|
|
(*ppenum)->Skip(mEnumVARIANTPosition); // QI addrefed
|
|
|
|
msaaAccessible->Release();
|
|
|
|
|
|
|
|
return NOERROR;
|
|
|
|
}
|
2006-02-28 14:35:50 +00:00
|
|
|
|
2003-04-01 20:02:51 +00:00
|
|
|
|
|
|
|
// For IDispatch support
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP
|
2003-04-01 20:02:51 +00:00
|
|
|
nsAccessibleWrap::GetTypeInfoCount(UINT *p)
|
|
|
|
{
|
|
|
|
*p = 0;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For IDispatch support
|
|
|
|
STDMETHODIMP nsAccessibleWrap::GetTypeInfo(UINT i, LCID lcid, ITypeInfo **ppti)
|
|
|
|
{
|
|
|
|
*ppti = 0;
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For IDispatch support
|
2006-02-28 14:35:50 +00:00
|
|
|
STDMETHODIMP
|
2003-04-01 20:02:51 +00:00
|
|
|
nsAccessibleWrap::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames,
|
|
|
|
UINT cNames, LCID lcid, DISPID *rgDispId)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// For IDispatch support
|
|
|
|
STDMETHODIMP nsAccessibleWrap::Invoke(DISPID dispIdMember, REFIID riid,
|
|
|
|
LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
|
|
|
|
VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP nsAccessibleWrap::GetNativeInterface(void **aOutAccessible)
|
|
|
|
{
|
|
|
|
*aOutAccessible = NS_STATIC_CAST(IAccessible*, this);
|
2005-09-02 01:33:23 +00:00
|
|
|
NS_ADDREF_THIS();
|
2003-04-01 20:02:51 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-04-16 20:23:00 +00:00
|
|
|
// nsPIAccessible
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aEvent);
|
|
|
|
|
|
|
|
nsresult rv = nsAccessible::FireAccessibleEvent(aEvent);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
PRUint32 eventType = 0;
|
|
|
|
aEvent->GetEventType(&eventType);
|
|
|
|
|
|
|
|
NS_ENSURE_TRUE(eventType > 0 &&
|
|
|
|
eventType < nsIAccessibleEvent::EVENT_LAST_ENTRY,
|
|
|
|
NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
PRUint32 winLastEntry = gWinEventMap[nsIAccessibleEvent::EVENT_LAST_ENTRY];
|
|
|
|
NS_ASSERTION(winLastEntry == kEVENT_LAST_ENTRY,
|
|
|
|
"MSAA event map skewed");
|
|
|
|
|
|
|
|
PRUint32 winEvent = gWinEventMap[eventType];
|
|
|
|
if (!winEvent)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
// Means we're not active.
|
|
|
|
NS_ENSURE_TRUE(mWeakShell, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAccessible> accessible;
|
|
|
|
aEvent->GetAccessible(getter_AddRefs(accessible));
|
|
|
|
if (!accessible)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
PRInt32 childID, worldID = OBJID_CLIENT;
|
|
|
|
PRUint32 role = ROLE_SYSTEM_TEXT; // Default value
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(accessible));
|
|
|
|
NS_ENSURE_STATE(accessNode);
|
|
|
|
|
|
|
|
HWND hWnd = 0;
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(accessible->GetRole(&role)) && role == ROLE_SYSTEM_CARET) {
|
|
|
|
childID = CHILDID_SELF;
|
|
|
|
worldID = OBJID_CARET;
|
|
|
|
} else {
|
|
|
|
childID = GetChildIDFor(accessible); // get the id for the accessible
|
|
|
|
if (!childID)
|
|
|
|
return NS_OK; // Can't fire an event without a child ID
|
|
|
|
|
|
|
|
// See if we're in a scrollable area with its own window
|
|
|
|
nsCOMPtr<nsIAccessible> newAccessible;
|
|
|
|
if (eventType == nsIAccessibleEvent::EVENT_HIDE) {
|
|
|
|
// Don't use frame from current accessible when we're hiding that
|
|
|
|
// accessible.
|
|
|
|
accessible->GetParent(getter_AddRefs(newAccessible));
|
|
|
|
} else {
|
|
|
|
newAccessible = accessible;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsPIAccessNode> privateAccessNode =
|
|
|
|
do_QueryInterface(newAccessible);
|
|
|
|
if (privateAccessNode) {
|
|
|
|
nsIFrame *frame = privateAccessNode->GetFrame();
|
|
|
|
if (frame)
|
|
|
|
hWnd = (HWND)frame->GetWindow()->GetNativeData(NS_NATIVE_WINDOW);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hWnd) {
|
|
|
|
void* handle = nsnull;
|
|
|
|
nsCOMPtr<nsIAccessibleDocument> accessibleDoc;
|
|
|
|
accessNode->GetAccessibleDocument(getter_AddRefs(accessibleDoc));
|
|
|
|
NS_ENSURE_STATE(accessibleDoc);
|
|
|
|
accessibleDoc->GetWindowHandle(&handle);
|
|
|
|
hWnd = (HWND)handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gecko uses two windows for every scrollable area. One window contains
|
|
|
|
// scrollbars and the child window contains only the client area.
|
|
|
|
// Details of the 2 window system:
|
|
|
|
// * Scrollbar window: caret drawing window & return value for WindowFromAccessibleObject()
|
|
|
|
// * Client area window: text drawing window & MSAA event window
|
|
|
|
|
|
|
|
// Fire MSAA event for client area window.
|
|
|
|
NotifyWinEvent(winEvent, hWnd, worldID, childID);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2006-02-28 14:35:50 +00:00
|
|
|
|
2003-04-01 20:02:51 +00:00
|
|
|
//------- Helper methods ---------
|
|
|
|
|
2007-04-16 20:23:00 +00:00
|
|
|
PRInt32 nsAccessibleWrap::GetChildIDFor(nsIAccessible* aAccessible)
|
|
|
|
{
|
|
|
|
// A child ID of the window is required, when we use NotifyWinEvent,
|
|
|
|
// so that the 3rd party application can call back and get the IAccessible
|
|
|
|
// the event occured on.
|
|
|
|
|
|
|
|
void *uniqueID;
|
|
|
|
nsCOMPtr<nsIAccessNode> accessNode(do_QueryInterface(aAccessible));
|
|
|
|
if (!accessNode) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
accessNode->GetUniqueID(&uniqueID);
|
|
|
|
|
|
|
|
// Yes, this means we're only compatibible with 32 bit
|
|
|
|
// MSAA is only available for 32 bit windows, so it's okay
|
|
|
|
return - NS_PTR_TO_INT32(uniqueID);
|
|
|
|
}
|
|
|
|
|
2003-04-01 20:02:51 +00:00
|
|
|
IDispatch *nsAccessibleWrap::NativeAccessible(nsIAccessible *aXPAccessible)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAccessibleWin32Object> accObject(do_QueryInterface(aXPAccessible));
|
|
|
|
if (accObject) {
|
|
|
|
void* hwnd;
|
|
|
|
accObject->GetHwnd(&hwnd);
|
|
|
|
if (hwnd) {
|
|
|
|
IDispatch *retval = nsnull;
|
2006-02-28 14:35:50 +00:00
|
|
|
AccessibleObjectFromWindow(NS_REINTERPRET_CAST(HWND, hwnd),
|
2005-03-30 00:53:10 +00:00
|
|
|
OBJID_WINDOW, IID_IAccessible, (void **) &retval);
|
2003-04-01 20:02:51 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
IAccessible *msaaAccessible;
|
|
|
|
aXPAccessible->GetNativeInterface((void**)&msaaAccessible);
|
|
|
|
|
|
|
|
return NS_STATIC_CAST(IDispatch*, msaaAccessible);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-04-15 08:45:55 +00:00
|
|
|
void nsAccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild, nsIAccessible **aXPAccessible)
|
2003-04-01 20:02:51 +00:00
|
|
|
{
|
2003-04-08 01:51:54 +00:00
|
|
|
*aXPAccessible = nsnull;
|
2003-04-15 08:45:55 +00:00
|
|
|
if (!mWeakShell)
|
|
|
|
return; // Fail, we don't want to do anything after we've shut down
|
2003-04-01 20:02:51 +00:00
|
|
|
|
|
|
|
// if its us real easy - this seems to always be the case
|
2003-04-15 08:45:55 +00:00
|
|
|
if (aVarChild.lVal == CHILDID_SELF) {
|
2003-04-01 20:02:51 +00:00
|
|
|
*aXPAccessible = NS_STATIC_CAST(nsIAccessible*, this);
|
2006-02-28 14:35:50 +00:00
|
|
|
}
|
2006-07-12 13:14:53 +00:00
|
|
|
else if (MustPrune(this)) {
|
|
|
|
return;
|
|
|
|
}
|
2003-04-01 20:02:51 +00:00
|
|
|
else {
|
|
|
|
// XXX It is rare to use a VARIANT with a child num
|
|
|
|
// so optimizing this is not a priority
|
|
|
|
// We can come back it do it later, if there are perf problems
|
|
|
|
// with a specific assistive technology
|
|
|
|
nsCOMPtr<nsIAccessible> xpAccessible, nextAccessible;
|
2003-07-31 08:09:39 +00:00
|
|
|
GetFirstChild(getter_AddRefs(xpAccessible));
|
2003-04-01 20:02:51 +00:00
|
|
|
for (PRInt32 index = 0; xpAccessible; index ++) {
|
2003-05-01 10:25:45 +00:00
|
|
|
if (!xpAccessible)
|
|
|
|
break; // Failed
|
2003-04-15 08:45:55 +00:00
|
|
|
if (aVarChild.lVal == index) {
|
2003-04-01 20:02:51 +00:00
|
|
|
*aXPAccessible = xpAccessible;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
nextAccessible = xpAccessible;
|
2003-07-31 08:09:39 +00:00
|
|
|
nextAccessible->GetNextSibling(getter_AddRefs(xpAccessible));
|
2003-04-01 20:02:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
NS_IF_ADDREF(*aXPAccessible);
|
|
|
|
}
|
|
|
|
|