Bug 754879 - reorg IEnumVariant implementation to traverse accessible children, r=tbsaunde, f=marcoz

This commit is contained in:
Alexander Surkov 2012-05-26 21:14:21 +09:00
parent c2094d8c7f
commit 346d10aff6
5 changed files with 230 additions and 157 deletions

View File

@ -0,0 +1,146 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "EnumVariant.h"
using namespace mozilla;
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// ChildrenEnumVariant
////////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
ChildrenEnumVariant::QueryInterface(REFIID aIID, void** aObject)
{
__try {
if (!aObject)
return E_INVALIDARG;
if (aIID == IID_IEnumVARIANT) {
*aObject = static_cast<IEnumVARIANT*>(this);
AddRef();
return S_OK;
}
if (aIID == IID_IUnknown) {
*aObject = static_cast<IUnknown*>(this);
AddRef();
return S_OK;
}
// Redirect QI to IAccessible this enum was retrieved for.
if (!mAnchorAcc->IsDefunct())
return mAnchorAcc->QueryInterface(aIID, aObject);
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(),
GetExceptionInformation())) { }
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE
ChildrenEnumVariant::AddRef()
{
return ++mRefCnt;
}
ULONG STDMETHODCALLTYPE
ChildrenEnumVariant::Release()
{
mRefCnt--;
ULONG r = mRefCnt;
if (r == 0)
delete this;
return r;
}
STDMETHODIMP
ChildrenEnumVariant::Next(ULONG aCount, VARIANT FAR* aItems,
ULONG FAR* aCountFetched)
{
__try {
if (!aItems || !aCountFetched)
return E_INVALIDARG;
*aCountFetched = 0;
if (mAnchorAcc->IsDefunct() || mAnchorAcc->GetChildAt(mCurIndex) != mCurAcc)
return CO_E_OBJNOTCONNECTED;
ULONG countFetched = 0;
for (; mCurAcc && countFetched < aCount; countFetched++) {
VariantInit(aItems + countFetched);
aItems[countFetched].pdispVal = nsAccessibleWrap::NativeAccessible(mCurAcc);
aItems[countFetched].vt = VT_DISPATCH;
mCurIndex++;
mCurAcc = mAnchorAcc->GetChildAt(mCurIndex);
}
(*aCountFetched) = countFetched;
return countFetched < aCount ? S_FALSE : S_OK;
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(),
GetExceptionInformation())) { }
return E_FAIL;
}
STDMETHODIMP
ChildrenEnumVariant::Skip(ULONG aCount)
{
__try {
if (mAnchorAcc->IsDefunct() || mAnchorAcc->GetChildAt(mCurIndex) != mCurAcc)
return CO_E_OBJNOTCONNECTED;
mCurIndex += aCount;
mCurAcc = mAnchorAcc->GetChildAt(mCurIndex);
return mCurAcc ? S_OK : S_FALSE;
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(),
GetExceptionInformation())) { }
return E_FAIL;
}
STDMETHODIMP
ChildrenEnumVariant::Reset()
{
__try {
if (mAnchorAcc->IsDefunct())
return CO_E_OBJNOTCONNECTED;
mCurIndex = 0;
mCurAcc = mAnchorAcc->GetChildAt(0);
return S_OK;
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(),
GetExceptionInformation())) { }
return E_FAIL;
}
STDMETHODIMP
ChildrenEnumVariant::Clone(IEnumVARIANT** aEnumVariant)
{
__try {
if (!aEnumVariant)
return E_INVALIDARG;
*aEnumVariant = new ChildrenEnumVariant(*this);
(*aEnumVariant)->AddRef();
return S_OK;
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(),
GetExceptionInformation())) { }
return E_FAIL;
}

View File

@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_a11y_EnumVariant_h__
#define mozilla_a11y_EnumVariant_h__
#include "nsAccessibleWrap.h"
namespace mozilla {
namespace a11y {
/**
* Used to fetch accessible children.
*/
class ChildrenEnumVariant MOZ_FINAL : public IEnumVARIANT
{
public:
ChildrenEnumVariant(nsAccessibleWrap* aAnchor) : mAnchorAcc(aAnchor),
mCurAcc(mAnchorAcc->GetChildAt(0)), mCurIndex(0), mRefCnt(0) { }
// IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(
/* [in] */ REFIID aRefIID,
/* [annotation][iid_is][out] */ void** aObject);
virtual ULONG STDMETHODCALLTYPE AddRef();
virtual ULONG STDMETHODCALLTYPE Release();
// IEnumVariant
virtual /* [local] */ HRESULT STDMETHODCALLTYPE Next(
/* [in] */ ULONG aCount,
/* [length_is][size_is][out] */ VARIANT* aItems,
/* [out] */ ULONG* aCountFetched);
virtual HRESULT STDMETHODCALLTYPE Skip(
/* [in] */ ULONG aCount);
virtual HRESULT STDMETHODCALLTYPE Reset();
virtual HRESULT STDMETHODCALLTYPE Clone(
/* [out] */ IEnumVARIANT** aEnumVaraint);
private:
ChildrenEnumVariant() MOZ_DELETE;
ChildrenEnumVariant& operator =(const ChildrenEnumVariant&) MOZ_DELETE;
ChildrenEnumVariant(const ChildrenEnumVariant& aEnumVariant) :
mAnchorAcc(aEnumVariant.mAnchorAcc), mCurAcc(aEnumVariant.mCurAcc),
mCurIndex(aEnumVariant.mCurIndex), mRefCnt(0) { }
virtual ~ChildrenEnumVariant() { }
protected:
nsRefPtr<nsAccessibleWrap> mAnchorAcc;
nsAccessible* mCurAcc;
PRUint32 mCurIndex;
private:
ULONG mRefCnt;
};
} // a11y namespace
} // mozilla namespace
#endif

View File

@ -29,18 +29,19 @@ CPPSRCS = \
nsHTMLImageAccessibleWrap.cpp \
nsHTMLTableAccessibleWrap.cpp \
nsWinUtils.cpp \
ia2AccessibleAction.cpp \
ia2AccessibleComponent.cpp \
ia2AccessibleImage.cpp \
CAccessibleText.cpp \
CAccessibleEditableText.cpp \
CAccessibleHyperlink.cpp \
ia2AccessibleHypertext.cpp \
ia2AccessibleRelation.cpp \
CAccessibleTable.cpp \
CAccessibleTableCell.cpp \
CAccessibleValue.cpp \
Compatibility.cpp \
EnumVariant.cpp \
ia2AccessibleAction.cpp \
ia2AccessibleComponent.cpp \
ia2AccessibleImage.cpp \
ia2AccessibleHypertext.cpp \
ia2AccessibleRelation.cpp \
RootAccessibleWrap.cpp \
TextLeafAccessibleWrap.cpp \
$(NULL)

View File

@ -6,6 +6,7 @@
#include "nsAccessibleWrap.h"
#include "Compatibility.h"
#include "EnumVariant.h"
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#include "nsWinUtils.h"
@ -64,22 +65,6 @@ static const PRInt32 kIEnumVariantDisconnected = -1;
ITypeInfo* nsAccessibleWrap::gTypeInfo = NULL;
//-----------------------------------------------------
// construction
//-----------------------------------------------------
nsAccessibleWrap::
nsAccessibleWrap(nsIContent* aContent, nsDocAccessible* aDoc) :
nsAccessible(aContent, aDoc), mEnumVARIANTPosition(0)
{
}
//-----------------------------------------------------
// destruction
//-----------------------------------------------------
nsAccessibleWrap::~nsAccessibleWrap()
{
}
NS_IMPL_ISUPPORTS_INHERITED0(nsAccessibleWrap, nsAccessible);
//-----------------------------------------------------
@ -95,10 +80,11 @@ __try {
if (IID_IUnknown == iid || IID_IDispatch == iid || IID_IAccessible == iid)
*ppv = static_cast<IAccessible*>(this);
else if (IID_IEnumVARIANT == iid) {
long numChildren;
get_accChildCount(&numChildren);
if (numChildren > 0) // Don't support this interface for leaf elements
*ppv = static_cast<IEnumVARIANT*>(this);
// Don't support this interface for leaf elements.
if (!HasChildren() || nsAccUtils::MustPrune(this))
return E_NOINTERFACE;
*ppv = static_cast<IEnumVARIANT*>(new ChildrenEnumVariant(this));
} else if (IID_IServiceProvider == iid)
*ppv = static_cast<IServiceProvider*>(this);
else if (IID_IAccessible2 == iid && !Compatibility::IsIA2Off())
@ -127,6 +113,7 @@ __try {
(reinterpret_cast<IUnknown*>(*ppv))->AddRef();
} __except(FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
return S_OK;
}
@ -998,91 +985,6 @@ STDMETHODIMP nsAccessibleWrap::put_accValue(
return E_NOTIMPL;
}
#include "mshtml.h"
////////////////////////////////////////////////////////////////////////////////
// nsAccessibleWrap. IEnumVariant
STDMETHODIMP
nsAccessibleWrap::Next(ULONG aNumElementsRequested, VARIANT FAR* aPVar,
ULONG FAR* aNumElementsFetched)
{
// Children already cached via QI to IEnumVARIANT
__try {
*aNumElementsFetched = 0;
if (aNumElementsRequested <= 0 || !aPVar)
return E_INVALIDARG;
if (mEnumVARIANTPosition == kIEnumVariantDisconnected)
return CO_E_OBJNOTCONNECTED;
PRUint32 numElementsFetched = 0;
for (; numElementsFetched < aNumElementsRequested;
numElementsFetched++, mEnumVARIANTPosition++) {
nsAccessible* accessible = GetChildAt(mEnumVARIANTPosition);
if (!accessible)
break;
VariantInit(&aPVar[numElementsFetched]);
aPVar[numElementsFetched].pdispVal = NativeAccessible(accessible);
aPVar[numElementsFetched].vt = VT_DISPATCH;
}
(*aNumElementsFetched) = numElementsFetched;
return numElementsFetched < aNumElementsRequested ? S_FALSE : S_OK;
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
return E_FAIL;
}
STDMETHODIMP
nsAccessibleWrap::Skip(ULONG aNumElements)
{
__try {
if (mEnumVARIANTPosition == kIEnumVariantDisconnected)
return CO_E_OBJNOTCONNECTED;
mEnumVARIANTPosition += aNumElements;
PRUint32 childCount = ChildCount();
if (mEnumVARIANTPosition > static_cast<PRInt32>(childCount))
{
mEnumVARIANTPosition = childCount;
return S_FALSE;
}
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
return NOERROR;
}
STDMETHODIMP
nsAccessibleWrap::Reset(void)
{
mEnumVARIANTPosition = 0;
return NOERROR;
}
STDMETHODIMP
nsAccessibleWrap::Clone(IEnumVARIANT FAR* FAR* ppenum)
{
__try {
*ppenum = nsnull;
nsCOMPtr<nsIArray> childArray;
nsresult rv = GetChildren(getter_AddRefs(childArray));
*ppenum = new AccessibleEnumerator(childArray);
if (!*ppenum)
return E_OUTOFMEMORY;
NS_ADDREF(*ppenum);
} __except(nsAccessNodeWrap::FilterA11yExceptions(::GetExceptionCode(), GetExceptionInformation())) { }
return NOERROR;
}
////////////////////////////////////////////////////////////////////////////////
// nsAccessibleWrap. IAccessible2
@ -1610,11 +1512,6 @@ nsAccessibleWrap::FirePlatformEvent(AccEvent* aEvent)
if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED ||
eventType == nsIAccessibleEvent::EVENT_FOCUS) {
UpdateSystemCaret();
} else if (eventType == nsIAccessibleEvent::EVENT_REORDER) {
// If the accessible children are changed then drop the IEnumVariant current
// position of the accessible.
UnattachIEnumVariant();
}
PRInt32 childID = GetChildIDFor(accessible); // get the id for the accessible
@ -1782,13 +1679,6 @@ nsAccessibleWrap::NativeAccessible(nsIAccessible* aAccessible)
return static_cast<IDispatch*>(msaaAccessible);
}
void
nsAccessibleWrap::UnattachIEnumVariant()
{
if (mEnumVARIANTPosition > 0)
mEnumVARIANTPosition = kIEnumVariantDisconnected;
}
nsAccessible*
nsAccessibleWrap::GetXPAccessibleFor(const VARIANT& aVarChild)
{

View File

@ -67,12 +67,12 @@ class nsAccessibleWrap : public nsAccessible,
public ia2AccessibleComponent,
public CAccessibleHyperlink,
public CAccessibleValue,
public IAccessible2,
public IEnumVARIANT
public IAccessible2
{
public: // construction, destruction
nsAccessibleWrap(nsIContent* aContent, nsDocAccessible* aDoc);
virtual ~nsAccessibleWrap();
nsAccessibleWrap(nsIContent* aContent, nsDocAccessible* aDoc) :
nsAccessible(aContent, aDoc) { }
virtual ~nsAccessibleWrap() { }
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
@ -235,25 +235,6 @@ public: // construction, destruction
virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_attributes(
/* [retval][out] */ BSTR *attributes);
public: // IEnumVariant
// 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.
virtual /* [local] */ HRESULT STDMETHODCALLTYPE Next(
/* [in] */ ULONG celt,
/* [length_is][size_is][out] */ VARIANT __RPC_FAR *rgVar,
/* [out] */ ULONG __RPC_FAR *pCeltFetched);
virtual HRESULT STDMETHODCALLTYPE Skip(
/* [in] */ ULONG celt);
virtual HRESULT STDMETHODCALLTYPE Reset( void);
virtual HRESULT STDMETHODCALLTYPE Clone(
/* [out] */ IEnumVARIANT __RPC_FAR *__RPC_FAR *ppEnum);
// IDispatch (support of scripting languages like VB)
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo);
@ -300,21 +281,9 @@ public: // construction, destruction
static IDispatch *NativeAccessible(nsIAccessible *aXPAccessible);
/**
* Drops the IEnumVariant current position so that navigation methods
* Next() and Skip() doesn't work until Reset() method is called. The method
* is used when children of the accessible are changed.
*/
void UnattachIEnumVariant();
protected:
virtual nsresult FirePlatformEvent(AccEvent* aEvent);
// mEnumVARIANTPosition not the current accessible's position, but a "cursor" of
// where we are in the current list of children, with respect to
// nsIEnumVariant::Reset(), Skip() and Next().
PRInt32 mEnumVARIANTPosition;
/**
* Creates ITypeInfo for LIBID_Accessibility if it's needed and returns it.
*/