bug 427841 - TreeViewChanged event fired on a particular tree table more than once breaks that table's AT-SPI hierarchy, patch by Alexander Surkov <surkov.alexander@gmail.com>, r=evan.yan

This commit is contained in:
Marco Zehe 2008-06-16 08:16:18 +02:00
Родитель 458d1f6305
Коммит 38408ae1a2
11 изменённых файлов: 111 добавлений и 46 удалений

Просмотреть файл

@ -47,7 +47,7 @@ interface nsIAccessible;
* *
* @status UNDER_REVIEW * @status UNDER_REVIEW
*/ */
[uuid(7e0f50b0-6444-4372-b00f-4ce81c6b058a)] [uuid(1dde5c3b-bede-43d1-aabf-dabc461113bd)]
interface nsIAccessibleTreeCache : nsISupports interface nsIAccessibleTreeCache : nsISupports
{ {
/** /**
@ -82,6 +82,12 @@ interface nsIAccessibleTreeCache : nsISupports
*/ */
void treeViewInvalidated(in long aStartRow, in long aEndRow, void treeViewInvalidated(in long aStartRow, in long aEndRow,
in long aStartCol, in long aEndCol); in long aStartCol, in long aEndCol);
/**
* Invalidates children created for previous tree view.
*/
void treeViewChanged();
}; };
[uuid(b71532f9-53b2-4647-a5b2-1c5f57e9aed6)] [uuid(b71532f9-53b2-4647-a5b2-1c5f57e9aed6)]

Просмотреть файл

@ -1102,12 +1102,18 @@ nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
nsresult rv = nsAccessible::FireAccessibleEvent(aEvent); nsresult rv = nsAccessible::FireAccessibleEvent(aEvent);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return FirePlatformEvent(aEvent);
}
nsresult
nsAccessibleWrap::FirePlatformEvent(nsIAccessibleEvent *aEvent)
{
nsCOMPtr<nsIAccessible> accessible; nsCOMPtr<nsIAccessible> accessible;
aEvent->GetAccessible(getter_AddRefs(accessible)); aEvent->GetAccessible(getter_AddRefs(accessible));
NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE); NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE);
PRUint32 type = 0; PRUint32 type = 0;
rv = aEvent->GetEventType(&type); nsresult rv = aEvent->GetEventType(&type);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
AtkObject *atkObj = nsAccessibleWrap::GetAtkObject(accessible); AtkObject *atkObj = nsAccessibleWrap::GetAtkObject(accessible);

Просмотреть файл

@ -116,6 +116,8 @@ public:
} }
protected: protected:
virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent);
nsresult FireAtkStateChangeEvent(nsIAccessibleEvent *aEvent, nsresult FireAtkStateChangeEvent(nsIAccessibleEvent *aEvent,
AtkObject *aObject); AtkObject *aObject);
nsresult FireAtkTextChangedEvent(nsIAccessibleEvent *aEvent, nsresult FireAtkTextChangedEvent(nsIAccessibleEvent *aEvent,

Просмотреть файл

@ -246,6 +246,16 @@ protected:
*/ */
nsresult GetAttrValue(nsIAtom *aAriaProperty, double *aValue); nsresult GetAttrValue(nsIAtom *aAriaProperty, double *aValue);
/**
* Fires platform accessible event. It's notification method only. It does
* change nothing on Gecko side. Mostly you should use
* nsIAccessible::FireAccessibleEvent excepting special cases like we have
* in xul:tree accessible to lie to AT. Must be overridden in wrap classes.
*
* @param aEvent the accessible event to fire.
*/
virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent) = 0;
// Data Members // Data Members
nsCOMPtr<nsIAccessible> mParent; nsCOMPtr<nsIAccessible> mParent;
nsIAccessible *mFirstChild, *mNextSibling; nsIAccessible *mFirstChild, *mNextSibling;

Просмотреть файл

@ -643,18 +643,6 @@ nsresult nsRootAccessible::HandleEventWithTarget(nsIDOMEvent* aEvent,
return NS_OK; return NS_OK;
} }
#ifdef MOZ_XUL
if (eventType.EqualsLiteral("TreeViewChanged")) { // Always asynch, always from user input
if (!isTree)
return NS_OK;
nsCOMPtr<nsIContent> treeContent = do_QueryInterface(aTargetNode);
nsAccEvent::PrepareForEvent(aTargetNode, PR_TRUE);
return accService->InvalidateSubtreeFor(eventShell, treeContent,
nsIAccessibleEvent::EVENT_DOM_SIGNIFICANT_CHANGE);
}
#endif
if (eventType.EqualsLiteral("popuphiding")) { if (eventType.EqualsLiteral("popuphiding")) {
// If accessible focus was on or inside popup that closes, // If accessible focus was on or inside popup that closes,
// then restore it to true current focus. // then restore it to true current focus.
@ -678,11 +666,22 @@ nsresult nsRootAccessible::HandleEventWithTarget(nsIDOMEvent* aEvent,
return NS_OK; return NS_OK;
#ifdef MOZ_XUL #ifdef MOZ_XUL
if (eventType.EqualsLiteral("TreeRowCountChanged")) if (isTree) {
return HandleTreeRowCountChangedEvent(aEvent, accessible, localName); nsCOMPtr<nsIAccessibleTreeCache> treeAcc(do_QueryInterface(accessible));
NS_ASSERTION(treeAcc,
if (eventType.EqualsLiteral("TreeInvalidated")) "Accessible for xul:tree doesn't implement nsIAccessibleTreeCache interface.");
return HandleTreeInvalidatedEvent(aEvent, accessible, localName);
if (treeAcc) {
if (eventType.EqualsLiteral("TreeViewChanged"))
return treeAcc->TreeViewChanged();
if (eventType.EqualsLiteral("TreeRowCountChanged"))
return HandleTreeRowCountChangedEvent(aEvent, treeAcc);
if (eventType.EqualsLiteral("TreeInvalidated"))
return HandleTreeInvalidatedEvent(aEvent, treeAcc);
}
}
#endif #endif
if (eventType.EqualsLiteral("RadioStateChange")) { if (eventType.EqualsLiteral("RadioStateChange")) {
@ -1095,12 +1094,8 @@ NS_IMETHODIMP nsRootAccessible::FireDocLoadEvents(PRUint32 aEventType)
nsresult nsresult
nsRootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent, nsRootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
nsIAccessible *aAccessible, nsIAccessibleTreeCache *aAccessible)
const nsAString& aTargetName)
{ {
if (!aTargetName.EqualsLiteral("tree"))
return NS_OK;
nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent)); nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
if (!dataEvent) if (!dataEvent)
return NS_OK; return NS_OK;
@ -1121,20 +1116,13 @@ nsRootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
indexVariant->GetAsInt32(&index); indexVariant->GetAsInt32(&index);
countVariant->GetAsInt32(&count); countVariant->GetAsInt32(&count);
nsCOMPtr<nsIAccessibleTreeCache> treeAccCache(do_QueryInterface(aAccessible)); return aAccessible->InvalidateCache(index, count);
NS_ENSURE_STATE(treeAccCache);
return treeAccCache->InvalidateCache(index, count);
} }
nsresult nsresult
nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent, nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
nsIAccessible *aAccessible, nsIAccessibleTreeCache *aAccessible)
const nsAString& aTargetName)
{ {
if (!aTargetName.EqualsLiteral("tree"))
return NS_OK;
nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent)); nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
if (!dataEvent) if (!dataEvent)
return NS_OK; return NS_OK;
@ -1165,9 +1153,6 @@ nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
if (endColVariant) if (endColVariant)
endColVariant->GetAsInt32(&endCol); endColVariant->GetAsInt32(&endCol);
nsCOMPtr<nsIAccessibleTreeCache> treeAcc(do_QueryInterface(aAccessible)); return aAccessible->TreeViewInvalidated(startRow, endRow, startCol, endCol);
NS_ENSURE_STATE(treeAcc);
return treeAcc->TreeViewInvalidated(startRow, endRow, startCol, endCol);
} }

Просмотреть файл

@ -38,9 +38,13 @@
#ifndef _nsRootAccessible_H_ #ifndef _nsRootAccessible_H_
#define _nsRootAccessible_H_ #define _nsRootAccessible_H_
#include "nsCaretAccessible.h"
#include "nsDocAccessibleWrap.h" #include "nsDocAccessibleWrap.h"
#include "nsHashtable.h"
#include "nsIAccessibleDocument.h" #include "nsIAccessibleDocument.h"
#include "nsIAccessibleTreeCache.h"
#include "nsHashtable.h"
#include "nsCaretAccessible.h" #include "nsCaretAccessible.h"
#include "nsIDocument.h" #include "nsIDocument.h"
#include "nsIDOMFocusListener.h" #include "nsIDOMFocusListener.h"
@ -124,15 +128,13 @@ class nsRootAccessible : public nsDocAccessibleWrap,
* Handles 'TreeRowCountChanged' event. Used in HandleEventWithTarget(). * Handles 'TreeRowCountChanged' event. Used in HandleEventWithTarget().
*/ */
nsresult HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent, nsresult HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
nsIAccessible *aAccessible, nsIAccessibleTreeCache *aAccessible);
const nsAString& aTargetName);
/** /**
* Handles 'TreeInvalidated' event. Used in HandleEventWithTarget(). * Handles 'TreeInvalidated' event. Used in HandleEventWithTarget().
*/ */
nsresult HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent, nsresult HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
nsIAccessible *aAccessible, nsIAccessibleTreeCache *aAccessible);
const nsAString& aTargetName);
#ifdef MOZ_XUL #ifdef MOZ_XUL
PRUint32 GetChromeFlags(); PRUint32 GetChromeFlags();

Просмотреть файл

@ -96,7 +96,9 @@ class nsAccessibleWrap : public nsAccessible
virtual already_AddRefed<nsIAccessible> GetUnignoredParent(); virtual already_AddRefed<nsIAccessible> GetUnignoredParent();
protected: protected:
virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent);
PRBool AncestorIsFlat() { PRBool AncestorIsFlat() {
// we don't create a native object if we're child of a "flat" accessible; for example, on OS X buttons // we don't create a native object if we're child of a "flat" accessible; for example, on OS X buttons
// shouldn't have any children, because that makes the OS confused. // shouldn't have any children, because that makes the OS confused.

Просмотреть файл

@ -169,8 +169,18 @@ nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
nsresult rv = nsAccessible::FireAccessibleEvent(aEvent); nsresult rv = nsAccessible::FireAccessibleEvent(aEvent);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return FirePlatformEvent(aEvent);
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
nsresult
nsAccessibleWrap::FirePlatformEvent(nsIAccessibleEvent *aEvent)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
PRUint32 eventType; PRUint32 eventType;
rv = aEvent->GetEventType(&eventType); nsresult rv = aEvent->GetEventType(&eventType);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// ignore everything but focus-changed and value-changed events for now. // ignore everything but focus-changed and value-changed events for now.

Просмотреть файл

@ -1690,6 +1690,12 @@ nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
nsresult rv = nsAccessible::FireAccessibleEvent(aEvent); nsresult rv = nsAccessible::FireAccessibleEvent(aEvent);
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
return FirePlatformEvent(aEvent);
}
nsresult
nsAccessibleWrap::FirePlatformEvent(nsIAccessibleEvent *aEvent)
{
PRUint32 eventType = 0; PRUint32 eventType = 0;
aEvent->GetEventType(&eventType); aEvent->GetEventType(&eventType);

Просмотреть файл

@ -313,6 +313,8 @@ class nsAccessibleWrap : public nsAccessible,
static IDispatch *NativeAccessible(nsIAccessible *aXPAccessible); static IDispatch *NativeAccessible(nsIAccessible *aXPAccessible);
protected: protected:
virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent);
// mEnumVARIANTPosition not the current accessible's position, but a "cursor" of // mEnumVARIANTPosition not the current accessible's position, but a "cursor" of
// where we are in the current list of children, with respect to // where we are in the current list of children, with respect to
// nsIEnumVariant::Reset(), Skip() and Next(). // nsIEnumVariant::Reset(), Skip() and Next().

Просмотреть файл

@ -636,7 +636,7 @@ nsXULTreeAccessible::TreeViewInvalidated(PRInt32 aStartRow, PRInt32 aEndRow,
{ {
NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE); NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
PRInt32 endRow = aEndRow, endCol = aEndCol; PRInt32 endRow = aEndRow;
nsresult rv; nsresult rv;
if (endRow == -1) { if (endRow == -1) {
@ -652,6 +652,8 @@ nsXULTreeAccessible::TreeViewInvalidated(PRInt32 aStartRow, PRInt32 aEndRow,
NS_ENSURE_STATE(treeColumns); NS_ENSURE_STATE(treeColumns);
#ifdef MOZ_ACCESSIBILITY_ATK #ifdef MOZ_ACCESSIBILITY_ATK
PRInt32 endCol = aEndCol;
if (endCol == -1) { if (endCol == -1) {
PRInt32 colCount = 0; PRInt32 colCount = 0;
rv = treeColumns->GetCount(&colCount); rv = treeColumns->GetCount(&colCount);
@ -705,6 +707,37 @@ nsXULTreeAccessible::TreeViewInvalidated(PRInt32 aStartRow, PRInt32 aEndRow,
return NS_OK; return NS_OK;
} }
// void nsIAccessibleTreeCache::treeViewChanged();
NS_IMETHODIMP
nsXULTreeAccessible::TreeViewChanged()
{
if (!mTree)
return NS_ERROR_FAILURE;
// Fire only notification destroy/create events on accessible tree to lie to
// AT because it should be expensive to fire destroy events for each tree item
// in cache.
nsCOMPtr<nsIAccessibleEvent> eventDestroy =
new nsAccEvent(nsIAccessibleEvent::EVENT_DOM_DESTROY,
this, PR_FALSE);
NS_ENSURE_TRUE(eventDestroy, NS_ERROR_OUT_OF_MEMORY);
nsresult rv = FirePlatformEvent(eventDestroy);
ClearCache(*mAccessNodeCache);
mTree->GetView(getter_AddRefs(mTreeView));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIAccessibleEvent> eventCreate =
new nsAccEvent(nsIAccessibleEvent::EVENT_DOM_CREATE,
this, PR_FALSE);
NS_ENSURE_TRUE(eventCreate, NS_ERROR_OUT_OF_MEMORY);
return FirePlatformEvent(eventCreate);
}
nsresult nsXULTreeAccessible::GetColumnCount(nsITreeBoxObject* aBoxObject, PRInt32* aCount) nsresult nsXULTreeAccessible::GetColumnCount(nsITreeBoxObject* aBoxObject, PRInt32* aCount)
{ {
NS_ENSURE_TRUE(aBoxObject, NS_ERROR_FAILURE); NS_ENSURE_TRUE(aBoxObject, NS_ERROR_FAILURE);
@ -714,7 +747,8 @@ nsresult nsXULTreeAccessible::GetColumnCount(nsITreeBoxObject* aBoxObject, PRInt
return treeColumns->GetCount(aCount); return treeColumns->GetCount(aCount);
} }
// ---------- nsXULTreeitemAccessible ---------- ////////////////////////////////////////////////////////////////////////////////
// nsXULTreeitemAccessible
nsXULTreeitemAccessible::nsXULTreeitemAccessible(nsIAccessible *aParent, nsIDOMNode *aDOMNode, nsIWeakReference *aShell, PRInt32 aRow, nsITreeColumn* aColumn) nsXULTreeitemAccessible::nsXULTreeitemAccessible(nsIAccessible *aParent, nsIDOMNode *aDOMNode, nsIWeakReference *aShell, PRInt32 aRow, nsITreeColumn* aColumn)
: nsLeafAccessible(aDOMNode, aShell) : nsLeafAccessible(aDOMNode, aShell)