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:
Родитель
458d1f6305
Коммит
38408ae1a2
|
@ -47,7 +47,7 @@ interface nsIAccessible;
|
|||
*
|
||||
* @status UNDER_REVIEW
|
||||
*/
|
||||
[uuid(7e0f50b0-6444-4372-b00f-4ce81c6b058a)]
|
||||
[uuid(1dde5c3b-bede-43d1-aabf-dabc461113bd)]
|
||||
interface nsIAccessibleTreeCache : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -82,6 +82,12 @@ interface nsIAccessibleTreeCache : nsISupports
|
|||
*/
|
||||
void treeViewInvalidated(in long aStartRow, in long aEndRow,
|
||||
in long aStartCol, in long aEndCol);
|
||||
|
||||
/**
|
||||
* Invalidates children created for previous tree view.
|
||||
*/
|
||||
void treeViewChanged();
|
||||
|
||||
};
|
||||
|
||||
[uuid(b71532f9-53b2-4647-a5b2-1c5f57e9aed6)]
|
||||
|
|
|
@ -1102,12 +1102,18 @@ nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
|
|||
nsresult rv = nsAccessible::FireAccessibleEvent(aEvent);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return FirePlatformEvent(aEvent);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAccessibleWrap::FirePlatformEvent(nsIAccessibleEvent *aEvent)
|
||||
{
|
||||
nsCOMPtr<nsIAccessible> accessible;
|
||||
aEvent->GetAccessible(getter_AddRefs(accessible));
|
||||
NS_ENSURE_TRUE(accessible, NS_ERROR_FAILURE);
|
||||
|
||||
PRUint32 type = 0;
|
||||
rv = aEvent->GetEventType(&type);
|
||||
nsresult rv = aEvent->GetEventType(&type);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
AtkObject *atkObj = nsAccessibleWrap::GetAtkObject(accessible);
|
||||
|
|
|
@ -116,6 +116,8 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent);
|
||||
|
||||
nsresult FireAtkStateChangeEvent(nsIAccessibleEvent *aEvent,
|
||||
AtkObject *aObject);
|
||||
nsresult FireAtkTextChangedEvent(nsIAccessibleEvent *aEvent,
|
||||
|
|
|
@ -246,6 +246,16 @@ protected:
|
|||
*/
|
||||
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
|
||||
nsCOMPtr<nsIAccessible> mParent;
|
||||
nsIAccessible *mFirstChild, *mNextSibling;
|
||||
|
|
|
@ -643,18 +643,6 @@ nsresult nsRootAccessible::HandleEventWithTarget(nsIDOMEvent* aEvent,
|
|||
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 accessible focus was on or inside popup that closes,
|
||||
// then restore it to true current focus.
|
||||
|
@ -678,11 +666,22 @@ nsresult nsRootAccessible::HandleEventWithTarget(nsIDOMEvent* aEvent,
|
|||
return NS_OK;
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
if (eventType.EqualsLiteral("TreeRowCountChanged"))
|
||||
return HandleTreeRowCountChangedEvent(aEvent, accessible, localName);
|
||||
|
||||
if (eventType.EqualsLiteral("TreeInvalidated"))
|
||||
return HandleTreeInvalidatedEvent(aEvent, accessible, localName);
|
||||
if (isTree) {
|
||||
nsCOMPtr<nsIAccessibleTreeCache> treeAcc(do_QueryInterface(accessible));
|
||||
NS_ASSERTION(treeAcc,
|
||||
"Accessible for xul:tree doesn't implement nsIAccessibleTreeCache interface.");
|
||||
|
||||
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
|
||||
|
||||
if (eventType.EqualsLiteral("RadioStateChange")) {
|
||||
|
@ -1095,12 +1094,8 @@ NS_IMETHODIMP nsRootAccessible::FireDocLoadEvents(PRUint32 aEventType)
|
|||
|
||||
nsresult
|
||||
nsRootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
|
||||
nsIAccessible *aAccessible,
|
||||
const nsAString& aTargetName)
|
||||
nsIAccessibleTreeCache *aAccessible)
|
||||
{
|
||||
if (!aTargetName.EqualsLiteral("tree"))
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
|
||||
if (!dataEvent)
|
||||
return NS_OK;
|
||||
|
@ -1121,20 +1116,13 @@ nsRootAccessible::HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
|
|||
indexVariant->GetAsInt32(&index);
|
||||
countVariant->GetAsInt32(&count);
|
||||
|
||||
nsCOMPtr<nsIAccessibleTreeCache> treeAccCache(do_QueryInterface(aAccessible));
|
||||
NS_ENSURE_STATE(treeAccCache);
|
||||
|
||||
return treeAccCache->InvalidateCache(index, count);
|
||||
return aAccessible->InvalidateCache(index, count);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
|
||||
nsIAccessible *aAccessible,
|
||||
const nsAString& aTargetName)
|
||||
nsIAccessibleTreeCache *aAccessible)
|
||||
{
|
||||
if (!aTargetName.EqualsLiteral("tree"))
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMDataContainerEvent> dataEvent(do_QueryInterface(aEvent));
|
||||
if (!dataEvent)
|
||||
return NS_OK;
|
||||
|
@ -1165,9 +1153,6 @@ nsRootAccessible::HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
|
|||
if (endColVariant)
|
||||
endColVariant->GetAsInt32(&endCol);
|
||||
|
||||
nsCOMPtr<nsIAccessibleTreeCache> treeAcc(do_QueryInterface(aAccessible));
|
||||
NS_ENSURE_STATE(treeAcc);
|
||||
|
||||
return treeAcc->TreeViewInvalidated(startRow, endRow, startCol, endCol);
|
||||
return aAccessible->TreeViewInvalidated(startRow, endRow, startCol, endCol);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,9 +38,13 @@
|
|||
#ifndef _nsRootAccessible_H_
|
||||
#define _nsRootAccessible_H_
|
||||
|
||||
#include "nsCaretAccessible.h"
|
||||
#include "nsDocAccessibleWrap.h"
|
||||
#include "nsHashtable.h"
|
||||
|
||||
#include "nsIAccessibleDocument.h"
|
||||
#include "nsIAccessibleTreeCache.h"
|
||||
|
||||
#include "nsHashtable.h"
|
||||
#include "nsCaretAccessible.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMFocusListener.h"
|
||||
|
@ -124,15 +128,13 @@ class nsRootAccessible : public nsDocAccessibleWrap,
|
|||
* Handles 'TreeRowCountChanged' event. Used in HandleEventWithTarget().
|
||||
*/
|
||||
nsresult HandleTreeRowCountChangedEvent(nsIDOMEvent *aEvent,
|
||||
nsIAccessible *aAccessible,
|
||||
const nsAString& aTargetName);
|
||||
nsIAccessibleTreeCache *aAccessible);
|
||||
|
||||
/**
|
||||
* Handles 'TreeInvalidated' event. Used in HandleEventWithTarget().
|
||||
*/
|
||||
nsresult HandleTreeInvalidatedEvent(nsIDOMEvent *aEvent,
|
||||
nsIAccessible *aAccessible,
|
||||
const nsAString& aTargetName);
|
||||
nsIAccessibleTreeCache *aAccessible);
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
PRUint32 GetChromeFlags();
|
||||
|
|
|
@ -96,7 +96,9 @@ class nsAccessibleWrap : public nsAccessible
|
|||
virtual already_AddRefed<nsIAccessible> GetUnignoredParent();
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
virtual nsresult FirePlatformEvent(nsIAccessibleEvent *aEvent);
|
||||
|
||||
PRBool AncestorIsFlat() {
|
||||
// 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.
|
||||
|
|
|
@ -169,8 +169,18 @@ nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
|
|||
nsresult rv = nsAccessible::FireAccessibleEvent(aEvent);
|
||||
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;
|
||||
rv = aEvent->GetEventType(&eventType);
|
||||
nsresult rv = aEvent->GetEventType(&eventType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// ignore everything but focus-changed and value-changed events for now.
|
||||
|
|
|
@ -1690,6 +1690,12 @@ nsAccessibleWrap::FireAccessibleEvent(nsIAccessibleEvent *aEvent)
|
|||
nsresult rv = nsAccessible::FireAccessibleEvent(aEvent);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return FirePlatformEvent(aEvent);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAccessibleWrap::FirePlatformEvent(nsIAccessibleEvent *aEvent)
|
||||
{
|
||||
PRUint32 eventType = 0;
|
||||
aEvent->GetEventType(&eventType);
|
||||
|
||||
|
|
|
@ -313,6 +313,8 @@ class nsAccessibleWrap : public nsAccessible,
|
|||
static IDispatch *NativeAccessible(nsIAccessible *aXPAccessible);
|
||||
|
||||
protected:
|
||||
virtual nsresult FirePlatformEvent(nsIAccessibleEvent *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().
|
||||
|
|
|
@ -636,7 +636,7 @@ nsXULTreeAccessible::TreeViewInvalidated(PRInt32 aStartRow, PRInt32 aEndRow,
|
|||
{
|
||||
NS_ENSURE_TRUE(mTree && mTreeView, NS_ERROR_FAILURE);
|
||||
|
||||
PRInt32 endRow = aEndRow, endCol = aEndCol;
|
||||
PRInt32 endRow = aEndRow;
|
||||
|
||||
nsresult rv;
|
||||
if (endRow == -1) {
|
||||
|
@ -652,6 +652,8 @@ nsXULTreeAccessible::TreeViewInvalidated(PRInt32 aStartRow, PRInt32 aEndRow,
|
|||
NS_ENSURE_STATE(treeColumns);
|
||||
|
||||
#ifdef MOZ_ACCESSIBILITY_ATK
|
||||
PRInt32 endCol = aEndCol;
|
||||
|
||||
if (endCol == -1) {
|
||||
PRInt32 colCount = 0;
|
||||
rv = treeColumns->GetCount(&colCount);
|
||||
|
@ -705,6 +707,37 @@ nsXULTreeAccessible::TreeViewInvalidated(PRInt32 aStartRow, PRInt32 aEndRow,
|
|||
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)
|
||||
{
|
||||
NS_ENSURE_TRUE(aBoxObject, NS_ERROR_FAILURE);
|
||||
|
@ -714,7 +747,8 @@ nsresult nsXULTreeAccessible::GetColumnCount(nsITreeBoxObject* aBoxObject, PRInt
|
|||
return treeColumns->GetCount(aCount);
|
||||
}
|
||||
|
||||
// ---------- nsXULTreeitemAccessible ----------
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsXULTreeitemAccessible
|
||||
|
||||
nsXULTreeitemAccessible::nsXULTreeitemAccessible(nsIAccessible *aParent, nsIDOMNode *aDOMNode, nsIWeakReference *aShell, PRInt32 aRow, nsITreeColumn* aColumn)
|
||||
: nsLeafAccessible(aDOMNode, aShell)
|
||||
|
|
Загрузка…
Ссылка в новой задаче