Files
Mozilla/mozilla/widget/src/windows/Accessible.cpp

1012 lines
27 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either 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"),
* 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 NPL, 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 NPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsIAccessible.h"
#include "nsIAccessibleDocument.h"
#include "nsIAccessibleSelectable.h"
#include "nsIAccessibilityService.h"
#include "Accessible.h"
#include "nsIWidget.h"
#include "nsWindow.h"
#include "nsCOMPtr.h"
#include "nsIAccessibleEventReceiver.h"
#include "nsReadableUtils.h"
#include "nsITextContent.h"
#include "nsIDocument.h"
#include "nsIXULDocument.h"
#include "nsIDOMDocument.h"
#include "nsIDOMDocumentType.h"
#include "nsINameSpaceManager.h"
#include "String.h"
// for the COM IEnumVARIANT solution in get_AccSelection()
#define _ATLBASE_IMPL
#include <atlbase.h>
extern CComModule _Module;
#define _ATLCOM_IMPL
#include <atlcom.h>
/* For documentation of the accessibility architecture,
* see http://lxr.mozilla.org/seamonkey/source/accessible/accessible-docs.html
*/
//#define DEBUG_LEAKS
#ifdef DEBUG_LEAKS
static gAccessibles = 0;
#endif
// {61044601-A811-4e2b-BBBA-17BFABD329D7}
EXTERN_C GUID CDECL CLSID_Accessible =
{ 0x61044601, 0xa811, 0x4e2b, { 0xbb, 0xba, 0x17, 0xbf, 0xab, 0xd3, 0x29, 0xd7 } };
/*
* Class Accessible
*/
CComModule _Module;
//-----------------------------------------------------
// construction
//-----------------------------------------------------
Accessible::Accessible(nsIAccessible* aAcc, nsIDOMNode* aNode, HWND aWnd): SimpleDOMNode(aAcc, aNode, aWnd)
{
mAccessible = aAcc; // The nsIAccessible we're proxying from
mWnd = aWnd; // The window handle, for NotifyWinEvent, or getting the accessible parent thru the window parent
m_cRef = 0; // for reference counting, so we know when to delete ourselves
// mCachedIndex and mCachedChild allows fast order(N) indexing of children when moving forward through the
// list 1 at a time,rather than going back to the first child each time, it can just get the next sibling
mCachedIndex = 0;
mCachedChild = NULL;
#ifdef DEBUG_LEAKS
printf("Accessibles=%d\n", ++gAccessibles);
#endif
}
//-----------------------------------------------------
// destruction
//-----------------------------------------------------
Accessible::~Accessible()
{
m_cRef = 0;
mAccessible = mCachedChild = nsnull;
#ifdef DEBUG_LEAKS
printf("Accessibles=%d\n", --gAccessibles);
#endif
}
//-----------------------------------------------------
// IUnknown interface methods - see iunknown.h for documentation
//-----------------------------------------------------
STDMETHODIMP Accessible::QueryInterface(REFIID iid, void** ppv)
{
*ppv = NULL;
if (IID_IUnknown == iid || IID_IDispatch == iid || IID_IAccessible == iid)
*ppv = NS_STATIC_CAST(IAccessible*, this);
if (NULL == *ppv)
return SimpleDOMNode::QueryInterface(iid,ppv);
(NS_REINTERPRET_CAST(IUnknown*, *ppv))->AddRef();
return S_OK;
}
//-----------------------------------------------------
STDMETHODIMP_(ULONG) Accessible::AddRef()
{
return SimpleDOMNode::AddRef();
}
//-----------------------------------------------------
STDMETHODIMP_(ULONG) Accessible::Release()
{
return SimpleDOMNode::Release();
}
HINSTANCE Accessible::gmAccLib = 0;
HINSTANCE Accessible::gmUserLib = 0;
LPFNACCESSIBLEOBJECTFROMWINDOW Accessible::gmAccessibleObjectFromWindow = 0;
LPFNLRESULTFROMOBJECT Accessible::gmLresultFromObject = 0;
LPFNNOTIFYWINEVENT Accessible::gmNotifyWinEvent = 0;
//-----------------------------------------------------
// IAccessible methods
//-----------------------------------------------------
STDMETHODIMP Accessible::AccessibleObjectFromWindow(
HWND hwnd,
DWORD dwObjectID,
REFIID riid,
void **ppvObject)
{
// open the dll dynamically
if (!gmAccLib)
gmAccLib =::LoadLibrary("OLEACC.DLL");
if (gmAccLib) {
if (!gmAccessibleObjectFromWindow)
gmAccessibleObjectFromWindow = (LPFNACCESSIBLEOBJECTFROMWINDOW)GetProcAddress(gmAccLib,"AccessibleObjectFromWindow");
if (gmAccessibleObjectFromWindow)
return gmAccessibleObjectFromWindow(hwnd, dwObjectID, riid, ppvObject);
}
return E_FAIL;
}
STDMETHODIMP Accessible::NotifyWinEvent(
DWORD event,
HWND hwnd,
LONG idObjectType,
LONG idObject)
{
// open the dll dynamically
if (!gmUserLib)
gmUserLib =::LoadLibrary("USER32.DLL");
if (gmUserLib) {
if (!gmNotifyWinEvent)
gmNotifyWinEvent = (LPFNNOTIFYWINEVENT)GetProcAddress(gmUserLib,"NotifyWinEvent");
if (gmNotifyWinEvent)
return gmNotifyWinEvent(event, hwnd, idObjectType, idObject);
}
return E_FAIL;
}
STDMETHODIMP_(LRESULT) Accessible::LresultFromObject(
REFIID riid,
WPARAM wParam,
LPUNKNOWN pAcc)
{
// open the dll dynamically
if (!gmAccLib)
gmAccLib =::LoadLibrary("OLEACC.DLL");
if (gmAccLib) {
if (!gmAccessibleObjectFromWindow)
gmLresultFromObject = (LPFNLRESULTFROMOBJECT)GetProcAddress(gmAccLib,"LresultFromObject");
if (gmLresultFromObject)
return gmLresultFromObject(riid,wParam,pAcc);
}
return 0;
}
STDMETHODIMP Accessible::get_accParent( IDispatch __RPC_FAR *__RPC_FAR *ppdispParent)
{
nsCOMPtr<nsIAccessible> parent(nsnull);
mAccessible->GetAccParent(getter_AddRefs(parent));
if (parent) {
IAccessible* a = NewAccessible(parent, nsnull, mWnd);
a->AddRef();
*ppdispParent = a;
return S_OK;
}
// if we have a widget but no parent nsIAccessible then we might have a native
// widget parent that could give us a IAccessible. Lets check.
HWND pWnd = ::GetParent(mWnd);
if (pWnd) {
// get the accessible.
void* ptr = nsnull;
HRESULT result = AccessibleObjectFromWindow(pWnd, OBJID_WINDOW, IID_IAccessible, &ptr);
if (SUCCEEDED(result)) {
IAccessible* a = (IAccessible*)ptr;
// got one? return it.
if (a) {
*ppdispParent = a;
return NS_OK;
}
}
}
*ppdispParent = NULL;
return E_FAIL;
}
STDMETHODIMP Accessible::get_accChildCount( long __RPC_FAR *pcountChildren)
{
PRInt32 count = 0;
mAccessible->GetAccChildCount(&count);
*pcountChildren = count;
return S_OK;
}
STDMETHODIMP Accessible::get_accChild(
/* [in] */ VARIANT varChild,
/* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispChild)
{
nsCOMPtr<nsIAccessible> a;
GetNSAccessibleFor(varChild,a);
if (a)
{
// if its us return us
if (a == mAccessible) {
*ppdispChild = this;
AddRef();
return S_OK;
}
// create a new one.
IAccessible* ia = NewAccessible(a, nsnull, mWnd);
ia->AddRef();
*ppdispChild = ia;
return S_OK;
}
*ppdispChild = NULL;
return E_FAIL;
}
STDMETHODIMP Accessible::get_accName(
/* [optional][in] */ VARIANT varChild,
/* [retval][out] */ BSTR __RPC_FAR *pszName)
{
*pszName = NULL;
nsCOMPtr<nsIAccessible> a;
GetNSAccessibleFor(varChild,a);
if (a) {
nsAutoString name;
nsresult rv = a->GetAccName(name);
if (NS_FAILED(rv))
return S_FALSE;
*pszName = ::SysAllocString(name.get());
}
return S_OK;
}
STDMETHODIMP Accessible::get_accValue(
/* [optional][in] */ VARIANT varChild,
/* [retval][out] */ BSTR __RPC_FAR *pszValue)
{
*pszValue = NULL;
nsCOMPtr<nsIAccessible> a;
GetNSAccessibleFor(varChild,a);
if (a) {
nsAutoString value;
nsresult rv = a->GetAccValue(value);
if (NS_FAILED(rv))
return S_FALSE;
*pszValue = ::SysAllocString(value.get());
}
return S_OK;
}
STDMETHODIMP Accessible::get_accDescription(
/* [optional][in] */ VARIANT varChild,
/* [retval][out] */ BSTR __RPC_FAR *pszDescription)
{
*pszDescription = NULL;
nsCOMPtr<nsIAccessible> a;
GetNSAccessibleFor(varChild,a);
if (a) {
nsAutoString description;
nsresult rv = a->GetAccDescription(description);
if (NS_FAILED(rv))
return S_FALSE;
*pszDescription = ::SysAllocString(description.get());
}
return S_OK;
}
STDMETHODIMP Accessible::get_accRole(
/* [optional][in] */ VARIANT varChild,
/* [retval][out] */ VARIANT __RPC_FAR *pvarRole)
{
VariantInit(pvarRole);
pvarRole->vt = VT_I4;
nsCOMPtr<nsIAccessible> a;
GetNSAccessibleFor(varChild,a);
if (!a)
return E_FAIL;
PRUint32 role = 0;
nsresult rv = a->GetAccRole(&role);
if (NS_FAILED(rv))
return E_FAIL;
pvarRole->lVal = role;
return S_OK;
}
STDMETHODIMP Accessible::get_accState(
/* [optional][in] */ VARIANT varChild,
/* [retval][out] */ VARIANT __RPC_FAR *pvarState)
{
VariantInit(pvarState);
pvarState->vt = VT_I4;
pvarState->lVal = 0;
nsCOMPtr<nsIAccessible> a;
GetNSAccessibleFor(varChild,a);
if (!a)
return E_FAIL;
PRUint32 state;
nsresult rv = a->GetAccState(&state);
if (NS_FAILED(rv))
return E_FAIL;
pvarState->lVal = state;
return S_OK;
}
STDMETHODIMP Accessible::get_accHelp(
/* [optional][in] */ VARIANT varChild,
/* [retval][out] */ BSTR __RPC_FAR *pszHelp)
{
*pszHelp = NULL;
return S_FALSE;
}
STDMETHODIMP Accessible::get_accHelpTopic(
/* [out] */ BSTR __RPC_FAR *pszHelpFile,
/* [optional][in] */ VARIANT varChild,
/* [retval][out] */ long __RPC_FAR *pidTopic)
{
*pszHelpFile = NULL;
*pidTopic = 0;
return S_FALSE;
}
STDMETHODIMP Accessible::get_accKeyboardShortcut(
/* [optional][in] */ VARIANT varChild,
/* [retval][out] */ BSTR __RPC_FAR *pszKeyboardShortcut)
{
*pszKeyboardShortcut = NULL;
return S_FALSE;
}
STDMETHODIMP Accessible::get_accFocus(
/* [retval][out] */ VARIANT __RPC_FAR *pvarChild)
{
// Return the current nsIAccessible that has focus
VariantInit(pvarChild);
nsCOMPtr<nsIAccessible> focusedAccessible;
if (NS_SUCCEEDED(mAccessible->GetAccFocused(getter_AddRefs(focusedAccessible)))) {
pvarChild->vt = VT_DISPATCH;
pvarChild->pdispVal = NewAccessible(focusedAccessible, nsnull, mWnd);
pvarChild->pdispVal->AddRef();
return S_OK;
}
pvarChild->vt = VT_EMPTY;
return E_FAIL;
}
/**
* This method is called when a client wants to know which children of a node
* are selected. Currently we only handle this for HTML selects, which are the
* only nsIAccessible objects to implement nsIAccessibleSelectable.
*
* 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
* of options selected, unless there are none selected in which case we return an empty
* VARIANT.
*
* The typedefs at the beginning set up the structure that will contain an array
* of the IAccessibles. It implements the IEnumVARIANT interface, allowing us to
* use it to return the IAccessibles in the VARIANT.
*
* We get the selected options from the select's accessible object and then put create
* IAccessible objects for them and put those in the CComObject<EnumeratorType>
* object. Then we put the CComObject<EnumeratorType> object in the VARIANT and return.
*
* returns a VT_EMPTY VARIANT if:
* - there are no options in the select
* - none of the options are selected
* - there is an error QIing to IEnumVARIANT
* - The object is not the type that can have children selected
*/
STDMETHODIMP Accessible::get_accSelection(
/* [retval][out] */ VARIANT __RPC_FAR *pvarChildren)
{
typedef VARIANT ItemType; /* type of the object to be stored in container */
typedef ItemType EnumeratorExposedType; /* the type of the item exposed by the enumerator interface */
typedef IEnumVARIANT EnumeratorInterface; /* a COM enumerator ( IEnumXXXXX ) interface */
typedef _Copy<EnumeratorExposedType> EnumeratorCopyPolicy; /* Copy policy class */
typedef CComEnum<EnumeratorInterface,
&__uuidof(EnumeratorInterface),
EnumeratorExposedType,
EnumeratorCopyPolicy > EnumeratorType;
IEnumVARIANT* pUnk = NULL;
CComObject<EnumeratorType>* pEnum = NULL;
VariantInit(pvarChildren);
pvarChildren->vt = VT_EMPTY;
nsCOMPtr<nsIAccessibleSelectable> select(do_QueryInterface(mAccessible));
if (select) { // do we have an nsIAccessibleSelectable?
// we have an accessible that can have children selected
nsCOMPtr<nsISupportsArray> selectedOptions;
// gets the selected options as nsIAccessibles.
select->GetSelectedChildren(getter_AddRefs(selectedOptions));
if (selectedOptions) { // false if the select has no children or none are selected
PRUint32 length;
selectedOptions->Count(&length);
CComVariant* optionArray = new CComVariant[length]; // needs to be a CComVariant to go into the EnumeratorType object
// 1) Populate an array to store in the enumeration
for (PRUint32 i = 0 ; i < length ; i++) {
nsCOMPtr<nsISupports> tempOption;
selectedOptions->GetElementAt(i,getter_AddRefs(tempOption)); // this expects an nsISupports
if (tempOption) {
nsCOMPtr<nsIAccessible> tempAccess(do_QueryInterface(tempOption));
if ( tempAccess ) {
optionArray[i] = NewAccessible(tempAccess, nsnull, mWnd);
}
}
}
// 2) Create and initialize the enumeration
HRESULT hr = CComObject<EnumeratorType>::CreateInstance(&pEnum);
pEnum->Init(&optionArray[0], &optionArray[length], NULL, AtlFlagCopy);
pEnum->QueryInterface(IID_IEnumVARIANT, reinterpret_cast<void**>(&pUnk));
delete [] optionArray; // clean up, the Init call copies the data (AtlFlagCopy)
// 3) Put the enumerator in the VARIANT
if (!pUnk)
return NS_ERROR_FAILURE;
pvarChildren->vt = VT_UNKNOWN; // this must be VT_UNKNOWN for an IEnumVARIANT
pvarChildren->punkVal = pUnk;
}
}
return S_OK;
}
STDMETHODIMP Accessible::get_accDefaultAction(
/* [optional][in] */ VARIANT varChild,
/* [retval][out] */ BSTR __RPC_FAR *pszDefaultAction)
{
*pszDefaultAction = NULL;
nsCOMPtr<nsIAccessible> a;
GetNSAccessibleFor(varChild,a);
if (a) {
nsAutoString defaultAction;
nsresult rv = a->GetAccActionName(0,defaultAction);
if (NS_FAILED(rv))
return S_FALSE;
*pszDefaultAction = ::SysAllocString(defaultAction.get());
}
return S_OK;
}
STDMETHODIMP Accessible::accSelect(
/* [in] */ long flagsSelect,
/* [optional][in] */ VARIANT varChild)
{
// currently only handle focus and selection
if (flagsSelect & (SELFLAG_TAKEFOCUS|SELFLAG_TAKESELECTION|SELFLAG_REMOVESELECTION))
{
if (flagsSelect & SELFLAG_TAKEFOCUS)
mAccessible->AccTakeFocus();
if (flagsSelect & SELFLAG_TAKESELECTION)
mAccessible->AccTakeSelection();
if (flagsSelect & SELFLAG_REMOVESELECTION)
mAccessible->AccRemoveSelection();
return S_OK;
}
return E_FAIL;
}
STDMETHODIMP Accessible::accLocation(
/* [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> a;
GetNSAccessibleFor(varChild,a);
if (a) {
PRInt32 x,y,w,h;
a->AccGetBounds(&x,&y,&w,&h);
POINT cpos;
cpos.x = x;
cpos.y = y;
*pxLeft = x;
*pyTop = y;
*pcxWidth = w;
*pcyHeight = h;
return S_OK;
}
return E_FAIL;
}
STDMETHODIMP Accessible::accNavigate(
/* [in] */ long navDir,
/* [optional][in] */ VARIANT varStart,
/* [retval][out] */ VARIANT __RPC_FAR *pvarEndUpAt)
{
VariantInit(pvarEndUpAt);
nsCOMPtr<nsIAccessible> acc;
switch(navDir) {
case NAVDIR_DOWN:
mAccessible->AccNavigateDown(getter_AddRefs(acc));
break;
case NAVDIR_FIRSTCHILD:
mAccessible->GetAccFirstChild(getter_AddRefs(acc));
break;
case NAVDIR_LASTCHILD:
mAccessible->GetAccLastChild(getter_AddRefs(acc));
break;
case NAVDIR_LEFT:
mAccessible->AccNavigateLeft(getter_AddRefs(acc));
break;
case NAVDIR_NEXT:
mAccessible->GetAccNextSibling(getter_AddRefs(acc));
break;
case NAVDIR_PREVIOUS:
mAccessible->GetAccPreviousSibling(getter_AddRefs(acc));
break;
case NAVDIR_RIGHT:
mAccessible->AccNavigateRight(getter_AddRefs(acc));
break;
case NAVDIR_UP:
mAccessible->AccNavigateUp(getter_AddRefs(acc));
break;
}
if (acc) {
IAccessible* a = NewAccessible(acc, nsnull, mWnd);
a->AddRef();
pvarEndUpAt->vt = VT_DISPATCH;
pvarEndUpAt->pdispVal = a;
return NS_OK;
} else {
pvarEndUpAt->vt = VT_EMPTY;
return E_FAIL;
}
}
STDMETHODIMP Accessible::accHitTest(
/* [in] */ long xLeft,
/* [in] */ long yTop,
/* [retval][out] */ VARIANT __RPC_FAR *pvarChild)
{
VariantInit(pvarChild);
// convert to window coords
nsCOMPtr<nsIAccessible> a;
xLeft = xLeft;
yTop = yTop;
mAccessible->AccGetAt(xLeft,yTop, getter_AddRefs(a));
// if we got a child
if (a)
{
// if the child is us
if (a == mAccessible) {
pvarChild->vt = VT_I4;
pvarChild->lVal = CHILDID_SELF;
} else { // its not create an Accessible for it.
pvarChild->vt = VT_DISPATCH;
pvarChild->pdispVal = NewAccessible(a, nsnull, mWnd);
pvarChild->pdispVal->AddRef();
}
} else {
// no child at that point
pvarChild->vt = VT_EMPTY;
return E_FAIL;
}
return S_OK;
}
STDMETHODIMP Accessible::accDoDefaultAction(
/* [optional][in] */ VARIANT varChild)
{
return NS_SUCCEEDED(mAccessible->AccDoAction(0))? NS_OK: DISP_E_MEMBERNOTFOUND;
}
STDMETHODIMP Accessible::put_accName(
/* [optional][in] */ VARIANT varChild,
/* [in] */ BSTR szName)
{
return E_NOTIMPL;
}
STDMETHODIMP Accessible::put_accValue(
/* [optional][in] */ VARIANT varChild,
/* [in] */ BSTR szValue)
{
return E_NOTIMPL;
}
// For IDispatch support
STDMETHODIMP
Accessible::GetTypeInfoCount(UINT *p)
{
*p = 0;
return E_NOTIMPL;
}
// For IDispatch support
STDMETHODIMP Accessible::GetTypeInfo(UINT i, LCID lcid, ITypeInfo **ppti)
{
*ppti = 0;
return E_NOTIMPL;
}
// For IDispatch support
STDMETHODIMP
Accessible::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames,
UINT cNames, LCID lcid, DISPID *rgDispId)
{
return E_NOTIMPL;
}
// For IDispatch support
STDMETHODIMP Accessible::Invoke(DISPID dispIdMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
return E_NOTIMPL;
}
//------- Helper methods ---------
IAccessible *Accessible::NewAccessible(nsIAccessible *aNSAcc, nsIDOMNode *aNode, HWND aWnd)
{
IAccessible *retval = nsnull;
if (aNSAcc) {
nsCOMPtr<nsIAccessibleDocument> accDoc(do_QueryInterface(aNSAcc));
if (accDoc) {
nsCOMPtr<nsIDocument> doc;
accDoc->GetDocument(getter_AddRefs(doc));
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(doc));
retval = new DocAccessible(aNSAcc, node, aWnd);
}
else
retval = new Accessible(aNSAcc, aNode, aWnd);
}
return retval;
}
void Accessible::GetNSAccessibleFor(VARIANT varChild, nsCOMPtr<nsIAccessible>& aAcc)
{
// if its us real easy
if (varChild.lVal == CHILDID_SELF) {
aAcc = mAccessible;
} else if (mCachedChild && varChild.lVal == mCachedIndex+1) {
// if the cachedIndex is not self and the if its the one right
// before the one we want to get. Then just ask it for its next.
nsCOMPtr<nsIAccessible> next;
mCachedChild->GetAccNextSibling(getter_AddRefs(next));
if (next) {
mCachedIndex++;
mCachedChild = next;
}
aAcc = next;
return;
} else {
// if the cachedindex is not the one right before we have to start at the begining
nsCOMPtr<nsIAccessible> a;
mAccessible->GetAccFirstChild(getter_AddRefs(mCachedChild));
mCachedIndex = 1;
while(mCachedChild)
{
if (varChild.lVal == mCachedIndex)
{
aAcc = mCachedChild;
return;
}
mCachedChild->GetAccNextSibling(getter_AddRefs(a));
mCachedChild = a;
mCachedIndex++;
}
aAcc = nsnull;
}
}
//----- DocAccessible -----
// Microsoft COM QueryInterface
STDMETHODIMP DocAccessible::QueryInterface(REFIID iid, void** ppv)
{
*ppv = NULL;
if (IID_IUnknown == iid || IID_IDispatch == iid || IID_ISimpleDOMDocument == iid)
*ppv = NS_STATIC_CAST(ISimpleDOMDocument*, this);
if (NULL == *ppv)
return Accessible::QueryInterface(iid,ppv);
(NS_REINTERPRET_CAST(IUnknown*, *ppv))->AddRef();
return S_OK;
}
NS_IMETHODIMP_(nsrefcnt)
DocAccessible::AddRef(void)
{
return Accessible::AddRef();
}
NS_IMETHODIMP_(nsrefcnt)
DocAccessible::Release(void)
{
return Accessible::Release();
}
DocAccessible::DocAccessible(nsIAccessible* aAcc, nsIDOMNode *aNode, HWND aWnd):Accessible(aAcc,aNode,aWnd)
{
}
DocAccessible::~DocAccessible()
{
}
STDMETHODIMP DocAccessible::get_URL(/* [out] */ BSTR __RPC_FAR *aURL)
{
nsCOMPtr<nsIAccessibleDocument> accDoc(do_QueryInterface(mAccessible));
if (accDoc) {
nsAutoString URL;
if (NS_SUCCEEDED(accDoc->GetURL(URL))) {
*aURL= ::SysAllocString(URL.get());
return S_OK;
}
}
return E_FAIL;
}
STDMETHODIMP DocAccessible::get_title( /* [out] */ BSTR __RPC_FAR *aTitle)
{
nsCOMPtr<nsIAccessibleDocument> accDoc(do_QueryInterface(mAccessible));
if (accDoc) {
nsAutoString title;
if (NS_SUCCEEDED(accDoc->GetTitle(title))) { // getter_Copies(pszTitle)))) {
*aTitle= ::SysAllocString(title.get());
return S_OK;
}
}
return E_FAIL;
}
STDMETHODIMP DocAccessible::get_mimeType(/* [out] */ BSTR __RPC_FAR *aMimeType)
{
nsCOMPtr<nsIAccessibleDocument> accDoc(do_QueryInterface(mAccessible));
if (accDoc) {
nsAutoString mimeType;
if (NS_SUCCEEDED(accDoc->GetMimeType(mimeType))) {
*aMimeType= ::SysAllocString(mimeType.get());
return S_OK;
}
}
return E_FAIL;
}
STDMETHODIMP DocAccessible::get_docType(/* [out] */ BSTR __RPC_FAR *aDocType)
{
nsCOMPtr<nsIAccessibleDocument> accDoc(do_QueryInterface(mAccessible));
if (accDoc) {
nsAutoString docType;
if (NS_SUCCEEDED(accDoc->GetDocType(docType))) {
*aDocType= ::SysAllocString(docType.get());
return S_OK;
}
}
return E_FAIL;
}
STDMETHODIMP DocAccessible::get_nameSpaceURIForID(/* [in] */ short aNameSpaceID,
/* [out] */ BSTR __RPC_FAR *aNameSpaceURI)
{
nsCOMPtr<nsIAccessibleDocument> accDoc(do_QueryInterface(mAccessible));
if (accDoc) {
*aNameSpaceURI = NULL;
nsAutoString nameSpaceURI;
if (NS_SUCCEEDED(accDoc->GetNameSpaceURIForID(aNameSpaceID, nameSpaceURI)))
*aNameSpaceURI = ::SysAllocString(nameSpaceURI.get());
return S_OK;
}
return E_FAIL;
}
STDMETHODIMP DocAccessible::put_alternateViewMediaTypes( /* [in] */ BSTR __RPC_FAR *commaSeparatedMediaTypes)
{
return E_NOTIMPL;
}
//----- Root Accessible -----
// XPCOM QueryInterface
NS_IMPL_QUERY_INTERFACE1(RootAccessible, nsIAccessibleEventListener)
// Microsoft COM QueryInterface
STDMETHODIMP RootAccessible::QueryInterface(REFIID iid, void** ppv)
{
*ppv = NULL;
if (IID_IUnknown == iid || IID_IDispatch == iid || IID_ISimpleDOMDocument == iid)
*ppv = NS_STATIC_CAST(ISimpleDOMDocument*, this);
if (NULL == *ppv)
return DocAccessible::QueryInterface(iid, ppv);
(NS_REINTERPRET_CAST(IUnknown*, *ppv))->AddRef();
return S_OK;
}
NS_IMETHODIMP_(nsrefcnt)
RootAccessible::AddRef(void)
{
return DocAccessible::AddRef();
}
NS_IMETHODIMP_(nsrefcnt)
RootAccessible::Release(void)
{
return DocAccessible::Release();
}
RootAccessible::RootAccessible(nsIAccessible* aAcc, HWND aWnd):DocAccessible(aAcc,nsnull,aWnd)
{
mListCount = 0;
mNextPos = 0;
nsCOMPtr<nsIAccessibleEventReceiver> r(do_QueryInterface(mAccessible));
if (r)
r->AddAccessibleEventListener(this);
}
RootAccessible::~RootAccessible()
{
nsCOMPtr<nsIAccessibleEventReceiver> r(do_QueryInterface(mAccessible));
if (r)
r->RemoveAccessibleEventListener();
// free up accessibles
for (int i=0; i < mListCount; i++)
mList[i].mAccessible = nsnull;
}
void RootAccessible::GetNSAccessibleFor(VARIANT varChild, nsCOMPtr<nsIAccessible>& aAcc)
{
// Check our circular array of event information, because the child ID
// asked for corresponds to an event target. See RootAccessible::HandleEvent to see how we provide this unique ID.
aAcc = nsnull;
if (varChild.lVal < 0) {
for (int i=0; i < mListCount; i++) {
if (varChild.lVal == mList[i].mId) {
aAcc = mList[i].mAccessible;
return;
}
}
}
Accessible::GetNSAccessibleFor(varChild, aAcc);
}
NS_IMETHODIMP RootAccessible::HandleEvent(PRUint32 aEvent, nsIAccessible* aAccessible)
{
// get the id for the accessible
PRInt32 id = GetIdFor(aAccessible);
// notify the window system
NotifyWinEvent(aEvent, mWnd, OBJID_CLIENT, id);
return NS_OK;
}
PRUint32 RootAccessible::GetIdFor(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.
// We use the unique ID exposed through nsIContent::GetContentID()
nsCOMPtr<nsIDOMNode> domNode;
aAccessible->AccGetDOMNode(getter_AddRefs(domNode));
PRUint32 uniqueID = - NS_REINTERPRET_CAST(PRInt32, (domNode.get()));
mList[mNextPos].mId = uniqueID;
mList[mNextPos].mAccessible = aAccessible;
if (++mNextPos >= MAX_LIST_SIZE)
mNextPos = 0;
if (mListCount < MAX_LIST_SIZE)
mListCount++;
return uniqueID;
}