Bug 418845 Enabling a11y massively degrades performance of dynamic <option> addition on Linux

r=aaronleventhal, surkov.alexander sr=neil a=dsicore


git-svn-id: svn://10.0.0.236/trunk@247971 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
ginn.chen%sun.com 2008-03-17 08:13:10 +00:00
parent 6a890a5336
commit e9a234c845
9 changed files with 242 additions and 108 deletions

View File

@ -319,8 +319,7 @@ PRBool
nsAccUtils::IsAncestorOf(nsIDOMNode *aPossibleAncestorNode,
nsIDOMNode *aPossibleDescendantNode)
{
NS_ENSURE_TRUE(aPossibleAncestorNode, PR_FALSE);
NS_ENSURE_TRUE(aPossibleDescendantNode, PR_FALSE);
NS_ENSURE_TRUE(aPossibleAncestorNode && aPossibleDescendantNode, PR_FALSE);
nsCOMPtr<nsIDOMNode> loopNode = aPossibleDescendantNode;
nsCOMPtr<nsIDOMNode> parentNode;
@ -334,6 +333,21 @@ nsAccUtils::IsAncestorOf(nsIDOMNode *aPossibleAncestorNode,
return PR_FALSE;
}
PRBool
nsAccUtils::AreSiblings(nsIDOMNode *aDOMNode1,
nsIDOMNode *aDOMNode2)
{
NS_ENSURE_TRUE(aDOMNode1 && aDOMNode2, PR_FALSE);
nsCOMPtr<nsIDOMNode> parentNode1, parentNode2;
if (NS_SUCCEEDED(aDOMNode1->GetParentNode(getter_AddRefs(parentNode1))) &&
NS_SUCCEEDED(aDOMNode2->GetParentNode(getter_AddRefs(parentNode2))) &&
parentNode1 == parentNode2) {
return PR_TRUE;
}
return PR_FALSE;
}
already_AddRefed<nsIAccessible>
nsAccUtils::GetAncestorWithRole(nsIAccessible *aDescendant, PRUint32 aRole)
{

View File

@ -148,6 +148,13 @@ public:
static PRBool IsAncestorOf(nsIDOMNode *aPossibleAncestorNode,
nsIDOMNode *aPossibleDescendantNode);
/**
* Are the first node and the second siblings?
* @return PR_TRUE if aDOMNode1 and aDOMNode2 have same parent
*/
static PRBool AreSiblings(nsIDOMNode *aDOMNode1,
nsIDOMNode *aDOMNode2);
/**
* If an ancestor in this document exists with the given role, return it
* @param aDescendant Descendant to start search with

View File

@ -57,18 +57,18 @@
PRBool nsAccEvent::gLastEventFromUserInput = PR_FALSE;
nsIDOMNode* nsAccEvent::gLastEventNodeWeak = 0;
NS_IMPL_ISUPPORTS1(nsAccEvent, nsIAccessibleEvent)
NS_IMPL_ISUPPORTS2(nsAccEvent, nsAccEvent, nsIAccessibleEvent)
nsAccEvent::nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
PRBool aIsAsynch):
mEventType(aEventType), mAccessible(aAccessible)
PRBool aIsAsynch, EEventRule aEventRule):
mEventType(aEventType), mAccessible(aAccessible), mEventRule(aEventRule)
{
CaptureIsFromUserInput(aIsAsynch);
}
nsAccEvent::nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode,
PRBool aIsAsynch):
mEventType(aEventType), mDOMNode(aDOMNode)
PRBool aIsAsynch, EEventRule aEventRule):
mEventType(aEventType), mDOMNode(aDOMNode), mEventRule(aEventRule)
{
CaptureIsFromUserInput(aIsAsynch);
}
@ -282,6 +282,94 @@ nsAccEvent::GetAccessibleByNode()
return accessible;
}
/* static */
void
nsAccEvent::ApplyEventRules(nsCOMArray<nsIAccessibleEvent> &aEventsToFire)
{
PRUint32 numQueuedEvents = aEventsToFire.Count();
for (PRInt32 tail = numQueuedEvents - 1; tail >= 0; tail --) {
nsRefPtr<nsAccEvent> tailEvent = GetAccEventPtr(aEventsToFire[tail]);
switch(tailEvent->mEventRule) {
case nsAccEvent::eCoalesceFromSameSubtree:
{
for (PRInt32 index = 0; index < tail; index ++) {
nsRefPtr<nsAccEvent> thisEvent = GetAccEventPtr(aEventsToFire[index]);
if (thisEvent->mEventType != tailEvent->mEventType)
continue; // Different type
if (thisEvent->mEventRule == nsAccEvent::eAllowDupes ||
thisEvent->mEventRule == nsAccEvent::eDoNotEmit)
continue; // Do not need to check
if (thisEvent->mDOMNode == tailEvent->mDOMNode) {
// Dupe
thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
continue;
}
if (nsAccUtils::IsAncestorOf(tailEvent->mDOMNode,
thisEvent->mDOMNode)) {
// thisDOMNode is a descendant of tailDOMNode
// Do not emit thisEvent, also apply this result to sibling
// nodes of thisDOMNode.
thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
ApplyToSiblings(aEventsToFire, 0, index, thisEvent->mEventType,
thisEvent->mDOMNode, nsAccEvent::eDoNotEmit);
continue;
}
if (nsAccUtils::IsAncestorOf(thisEvent->mDOMNode,
tailEvent->mDOMNode)) {
// tailDOMNode is a descendant of thisDOMNode
// Do not emit tailEvent, also apply this result to sibling
// nodes of tailDOMNode.
tailEvent->mEventRule = nsAccEvent::eDoNotEmit;
ApplyToSiblings(aEventsToFire, 0, tail, tailEvent->mEventType,
tailEvent->mDOMNode, nsAccEvent::eDoNotEmit);
break;
}
} // for (index)
if (tailEvent->mEventRule != nsAccEvent::eDoNotEmit) {
// Not in another event node's subtree, and no other event is in
// this event node's subtree.
// This event should be emitted
// Apply this result to sibling nodes of tailDOMNode
ApplyToSiblings(aEventsToFire, 0, tail, tailEvent->mEventType,
tailEvent->mDOMNode, nsAccEvent::eAllowDupes);
}
} break; // case eCoalesceFromSameSubtree
case nsAccEvent::eRemoveDupes:
{
// Check for repeat events.
for (PRInt32 index = 0; index < tail; index ++) {
nsRefPtr<nsAccEvent> accEvent = GetAccEventPtr(aEventsToFire[index]);
if (accEvent->mEventType == tailEvent->mEventType &&
accEvent->mEventRule == tailEvent->mEventRule &&
accEvent->mDOMNode == tailEvent->mDOMNode) {
accEvent->mEventRule = nsAccEvent::eDoNotEmit;
}
}
} break; // case eRemoveDupes
} // switch
} // for (tail)
}
/* static */
void
nsAccEvent::ApplyToSiblings(nsCOMArray<nsIAccessibleEvent> &aEventsToFire,
PRUint32 aStart, PRUint32 aEnd,
PRUint32 aEventType, nsIDOMNode* aDOMNode,
EEventRule aEventRule)
{
for (PRUint32 index = aStart; index < aEnd; index ++) {
nsRefPtr<nsAccEvent> accEvent = GetAccEventPtr(aEventsToFire[index]);
if (accEvent->mEventType == aEventType &&
accEvent->mEventRule != nsAccEvent::eDoNotEmit &&
nsAccUtils::AreSiblings(accEvent->mDOMNode, aDOMNode)) {
accEvent->mEventRule = aEventRule;
}
}
}
// nsAccStateChangeEvent
NS_IMPL_ISUPPORTS_INHERITED1(nsAccStateChangeEvent, nsAccEvent,

View File

@ -41,7 +41,9 @@
#ifndef _nsAccessibleEventData_H_
#define _nsAccessibleEventData_H_
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "nsIAccessibleEvent.h"
#include "nsIAccessible.h"
#include "nsIAccessibleDocument.h"
@ -50,13 +52,45 @@
class nsIPresShell;
#define NS_ACCEVENT_IMPL_CID \
{ /* 55b89892-a83d-4252-ba78-cbdf53a86936 */ \
0x55b89892, \
0xa83d, \
0x4252, \
{ 0xba, 0x78, 0xcb, 0xdf, 0x53, 0xa8, 0x69, 0x36 } \
}
class nsAccEvent: public nsIAccessibleEvent
{
public:
// Rule for accessible events.
// The rule will be applied when flushing pending events.
enum EEventRule {
// eAllowDupes : More than one event of the same type is allowed.
// This event will always be emitted.
eAllowDupes,
// eCoalesceFromSameSubtree : For events of the same type from the same
// subtree or the same node, only the umbrelle event on the ancestor
// will be emitted.
eCoalesceFromSameSubtree,
// eRemoveDupes : For repeat events, only the newest event in queue
// will be emitted.
eRemoveDupes,
// eDoNotEmit : This event is confirmed as a duplicate, do not emit it.
eDoNotEmit
};
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ACCEVENT_IMPL_CID)
// Initialize with an nsIAccessible
nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible, PRBool aIsAsynch = PR_FALSE);
nsAccEvent(PRUint32 aEventType, nsIAccessible *aAccessible,
PRBool aIsAsynch = PR_FALSE,
EEventRule aEventRule = eRemoveDupes);
// Initialize with an nsIDOMNode
nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode, PRBool aIsAsynch = PR_FALSE);
nsAccEvent(PRUint32 aEventType, nsIDOMNode *aDOMNode,
PRBool aIsAsynch = PR_FALSE,
EEventRule aEventRule = eRemoveDupes);
virtual ~nsAccEvent() {}
NS_DECL_ISUPPORTS
@ -73,6 +107,7 @@ protected:
private:
PRUint32 mEventType;
EEventRule mEventRule;
nsCOMPtr<nsIAccessible> mAccessible;
nsCOMPtr<nsIDOMNode> mDOMNode;
nsCOMPtr<nsIAccessibleDocument> mDocAccessible;
@ -81,6 +116,21 @@ private:
static nsIDOMNode* gLastEventNodeWeak;
public:
static PRUint32 EventType(nsIAccessibleEvent *aAccEvent) {
PRUint32 eventType;
aAccEvent->GetEventType(&eventType);
return eventType;
}
static EEventRule EventRule(nsIAccessibleEvent *aAccEvent) {
nsRefPtr<nsAccEvent> accEvent = GetAccEventPtr(aAccEvent);
return accEvent->mEventRule;
}
static PRBool IsFromUserInput(nsIAccessibleEvent *aAccEvent) {
PRBool isFromUserInput;
aAccEvent->GetIsFromUserInput(&isFromUserInput);
return isFromUserInput;
}
static void ResetLastInputState()
{gLastEventFromUserInput = PR_FALSE; gLastEventNodeWeak = nsnull; }
@ -103,8 +153,41 @@ public:
*/
static void PrepareForEvent(nsIAccessibleEvent *aEvent,
PRBool aForceIsFromUserInput = PR_FALSE);
/**
* Apply event rules to pending events, this method is called in
* FlushingPendingEvents().
* Result of this method:
* Event rule of filtered events will be set to eDoNotEmit.
* Events with other event rule are good to emit.
*/
static void ApplyEventRules(nsCOMArray<nsIAccessibleEvent> &aEventsToFire);
private:
static already_AddRefed<nsAccEvent> GetAccEventPtr(nsIAccessibleEvent *aAccEvent) {
nsAccEvent* accEvent = nsnull;
aAccEvent->QueryInterface(NS_GET_IID(nsAccEvent), (void**)&accEvent);
return accEvent;
}
/**
* Apply aEventRule to same type event that from sibling nodes of aDOMNode.
* @param aEventsToFire array of pending events
* @param aStart start index of pending events to be scanned
* @param aEnd end index to be scanned (not included)
* @param aEventType target event type
* @param aDOMNode target are siblings of this node
* @param aEventRule the event rule to be applied
* (should be eDoNotEmit or eAllowDupes)
*/
static void ApplyToSiblings(nsCOMArray<nsIAccessibleEvent> &aEventsToFire,
PRUint32 aStart, PRUint32 aEnd,
PRUint32 aEventType, nsIDOMNode* aDOMNode,
EEventRule aEventRule);
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsAccEvent, NS_ACCEVENT_IMPL_CID)
class nsAccStateChangeEvent: public nsAccEvent,
public nsIAccessibleStateChangeEvent
{

View File

@ -244,7 +244,7 @@ NS_IMETHODIMP nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument *aDoc, ns
new nsAccCaretMoveEvent(focusNode);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
return mRootAccessible->FireDelayedAccessibleEvent(event, nsDocAccessible::eRemoveDupes);
return mRootAccessible->FireDelayedAccessibleEvent(event);
}
nsRect

View File

@ -1064,7 +1064,7 @@ nsDocAccessible::AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID
if (aAttribute == nsAccessibilityAtoms::alt ||
aAttribute == nsAccessibilityAtoms::title) {
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_NAME_CHANGE,
targetNode, eRemoveDupes);
targetNode);
return;
}
@ -1086,7 +1086,8 @@ nsDocAccessible::AttributeChangedImpl(nsIContent* aContent, PRInt32 aNameSpaceID
multiSelectAccessNode->GetDOMNode(getter_AddRefs(multiSelectDOMNode));
NS_ASSERTION(multiSelectDOMNode, "A new accessible without a DOM node!");
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN,
multiSelectDOMNode, eAllowDupes);
multiSelectDOMNode,
nsAccEvent::eAllowDupes);
static nsIContent::AttrValuesArray strings[] =
{&nsAccessibilityAtoms::_empty, &nsAccessibilityAtoms::_false, nsnull};
@ -1437,93 +1438,29 @@ nsDocAccessible::CreateTextChangeEventForNode(nsIAccessible *aContainerAccessibl
nsresult nsDocAccessible::FireDelayedToolkitEvent(PRUint32 aEvent,
nsIDOMNode *aDOMNode,
EDupeEventRule aAllowDupes,
nsAccEvent::EEventRule aAllowDupes,
PRBool aIsAsynch)
{
nsCOMPtr<nsIAccessibleEvent> event =
new nsAccEvent(aEvent, aDOMNode, aIsAsynch);
new nsAccEvent(aEvent, aDOMNode, aIsAsynch, aAllowDupes);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
return FireDelayedAccessibleEvent(event, aAllowDupes);
return FireDelayedAccessibleEvent(event);
}
nsresult
nsDocAccessible::FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent,
EDupeEventRule aAllowDupes)
nsDocAccessible::FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent)
{
NS_ENSURE_TRUE(aEvent, NS_ERROR_FAILURE);
PRBool isTimerStarted = PR_TRUE;
PRInt32 numQueuedEvents = mEventsToFire.Count();
if (!mFireEventTimer) {
// Do not yet have a timer going for firing another event.
mFireEventTimer = do_CreateInstance("@mozilla.org/timer;1");
NS_ENSURE_TRUE(mFireEventTimer, NS_ERROR_OUT_OF_MEMORY);
}
PRUint32 newEventType;
aEvent->GetEventType(&newEventType);
nsCOMPtr<nsIDOMNode> newEventDOMNode;
aEvent->GetDOMNode(getter_AddRefs(newEventDOMNode));
if (numQueuedEvents == 0) {
isTimerStarted = PR_FALSE;
} else if (aAllowDupes == eCoalesceFromSameSubtree) {
// Especially for mutation events, we will define a duplicate event
// as one on the same node or on a descendant node.
// This prevents a flood of events when a subtree is changed.
for (PRInt32 index = 0; index < numQueuedEvents; index ++) {
nsIAccessibleEvent *accessibleEvent = mEventsToFire[index];
NS_ASSERTION(accessibleEvent, "Array item is not an accessible event");
if (!accessibleEvent) {
continue;
}
PRUint32 eventType;
accessibleEvent->GetEventType(&eventType);
if (eventType == newEventType) {
nsCOMPtr<nsIDOMNode> domNode;
accessibleEvent->GetDOMNode(getter_AddRefs(domNode));
if (newEventDOMNode == domNode || nsAccUtils::IsAncestorOf(newEventDOMNode, domNode)) {
mEventsToFire.RemoveObjectAt(index);
// The other event is the same type, but in a descendant of this
// event, so remove that one. The umbrella event in the ancestor
// is already enough
-- index;
-- numQueuedEvents;
}
else if (nsAccUtils::IsAncestorOf(domNode, newEventDOMNode)) {
// There is a better SHOW/HIDE event (it's in an ancestor)
return NS_OK;
}
}
}
} else if (aAllowDupes == eRemoveDupes) {
// Check for repeat events. If a redundant event exists remove
// original and put the new event at the end of the queue
// so it is fired after the others
for (PRInt32 index = 0; index < numQueuedEvents; index ++) {
nsIAccessibleEvent *accessibleEvent = mEventsToFire[index];
NS_ASSERTION(accessibleEvent, "Array item is not an accessible event");
if (!accessibleEvent) {
continue;
}
PRUint32 eventType;
accessibleEvent->GetEventType(&eventType);
if (eventType == newEventType) {
nsCOMPtr<nsIDOMNode> domNode;
accessibleEvent->GetDOMNode(getter_AddRefs(domNode));
if (domNode == newEventDOMNode) {
mEventsToFire.RemoveObjectAt(index);
-- index;
-- numQueuedEvents;
}
}
}
}
mEventsToFire.AppendObject(aEvent);
if (!isTimerStarted) {
if (mEventsToFire.Count() == 1) {
// This is be the first delayed event in queue, start timer
// so that event gets fired via FlushEventsCallback
NS_ADDREF_THIS(); // Kung fu death grip to prevent crash in callback
@ -1542,20 +1479,22 @@ NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
if (!presShell)
length = 0; // The doc is now shut down, don't fire events in it anymore
PRUint32 index;
for (index = 0; index < length; index ++) {
else
nsAccEvent::ApplyEventRules(mEventsToFire);
for (PRUint32 index = 0; index < length; index ++) {
nsCOMPtr<nsIAccessibleEvent> accessibleEvent(
do_QueryInterface(mEventsToFire[index]));
NS_ASSERTION(accessibleEvent, "Array item is not an accessible event");
if (nsAccEvent::EventRule(accessibleEvent) == nsAccEvent::eDoNotEmit)
continue;
nsCOMPtr<nsIAccessible> accessible;
accessibleEvent->GetAccessible(getter_AddRefs(accessible));
nsCOMPtr<nsIDOMNode> domNode;
accessibleEvent->GetDOMNode(getter_AddRefs(domNode));
PRUint32 eventType;
accessibleEvent->GetEventType(&eventType);
PRBool isFromUserInput;
accessibleEvent->GetIsFromUserInput(&isFromUserInput);
PRUint32 eventType = nsAccEvent::EventType(accessibleEvent);
PRBool isFromUserInput = nsAccEvent::IsFromUserInput(accessibleEvent);
if (domNode == gLastFocusedNode &&
eventType == nsIAccessibleEvent::EVENT_ASYNCH_HIDE ||
@ -1978,14 +1917,16 @@ NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
PRUint32 additionEvent = isAsynch ? nsIAccessibleEvent::EVENT_ASYNCH_SHOW :
nsIAccessibleEvent::EVENT_DOM_CREATE;
FireDelayedToolkitEvent(additionEvent, childNode,
eCoalesceFromSameSubtree, isAsynch);
nsAccEvent::eCoalesceFromSameSubtree,
isAsynch);
// Check to see change occured in an ARIA menu, and fire
// an EVENT_MENUPOPUP_START if it did.
nsRoleMapEntry *roleMapEntry = nsAccUtils::GetRoleMapEntry(childNode);
if (roleMapEntry && roleMapEntry->role == nsIAccessibleRole::ROLE_MENUPOPUP) {
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_MENUPOPUP_START,
childNode, eRemoveDupes, isAsynch);
childNode, nsAccEvent::eRemoveDupes,
isAsynch);
}
// Check to see if change occured inside an alert, and fire an EVENT_ALERT if it did
@ -1994,7 +1935,7 @@ NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
if (roleMapEntry && roleMapEntry->role == nsIAccessibleRole::ROLE_ALERT) {
nsCOMPtr<nsIDOMNode> alertNode(do_QueryInterface(ancestor));
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_ALERT, alertNode,
eRemoveDupes, isAsynch);
nsAccEvent::eRemoveDupes, isAsynch);
break;
}
ancestor = ancestor->GetParent();
@ -2012,9 +1953,10 @@ NS_IMETHODIMP nsDocAccessible::InvalidateCacheSubtree(nsIContent *aChild,
// from SHOW and HIDE so that they don't fetch extra objects
if (childAccessible) {
nsCOMPtr<nsIAccessibleEvent> reorderEvent =
new nsAccEvent(nsIAccessibleEvent::EVENT_REORDER, containerAccessible, isAsynch);
new nsAccEvent(nsIAccessibleEvent::EVENT_REORDER, containerAccessible,
isAsynch, nsAccEvent::eCoalesceFromSameSubtree);
NS_ENSURE_TRUE(reorderEvent, NS_ERROR_OUT_OF_MEMORY);
FireDelayedAccessibleEvent(reorderEvent, eCoalesceFromSameSubtree);
FireDelayedAccessibleEvent(reorderEvent);
}
}
@ -2090,13 +2032,14 @@ nsDocAccessible::FireShowHideEvents(nsIDOMNode *aDOMNode, PRBool aAvoidOnThisNod
aEventType == nsIAccessibleEvent::EVENT_ASYNCH_SHOW;
nsCOMPtr<nsIAccessibleEvent> event =
new nsAccEvent(aEventType, accessible, isAsynch);
new nsAccEvent(aEventType, accessible, isAsynch,
nsAccEvent::eCoalesceFromSameSubtree);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
if (aForceIsFromUserInput) {
nsAccEvent::PrepareForEvent(event, aForceIsFromUserInput);
}
if (aDelay) {
return FireDelayedAccessibleEvent(event, eCoalesceFromSameSubtree);
return FireDelayedAccessibleEvent(event);
}
return FireAccessibleEvent(event);
}

View File

@ -103,8 +103,6 @@ class nsDocAccessible : public nsHyperTextAccessibleWrap,
// nsIAccessibleText
NS_IMETHOD GetAssociatedEditor(nsIEditor **aEditor);
enum EDupeEventRule { eAllowDupes, eCoalesceFromSameSubtree, eRemoveDupes };
/**
* Non-virtual method to fire a delayed event after a 0 length timeout
*
@ -120,19 +118,15 @@ class nsDocAccessible : public nsHyperTextAccessibleWrap,
* synchronous with a DOM event
*/
nsresult FireDelayedToolkitEvent(PRUint32 aEvent, nsIDOMNode *aDOMNode,
EDupeEventRule aAllowDupes = eRemoveDupes,
nsAccEvent::EEventRule aAllowDupes = nsAccEvent::eRemoveDupes,
PRBool aIsAsynch = PR_FALSE);
/**
* Fire accessible event in timeout.
*
* @param aEvent - the event to fire
* @param aAllowDupes - if false then delayed events of the same type and
* for the same DOM node in the event queue won't
* be fired.
*/
nsresult FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent,
EDupeEventRule aAllowDupes = eRemoveDupes);
nsresult FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent);
void ShutdownChildDocuments(nsIDocShellTreeItem *aStart);

View File

@ -408,8 +408,7 @@ void nsRootAccessible::TryFireEarlyLoadEvent(nsIDOMNode *aDocNode)
NS_ASSERTION(rootContentTreeItem, "No root content tree item");
if (rootContentTreeItem == treeItem) {
// No frames or iframes, so we can fire the doc load finished event early
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_INTERNAL_LOAD, aDocNode,
eRemoveDupes);
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_INTERNAL_LOAD, aDocNode);
}
}
@ -506,9 +505,10 @@ PRBool nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
}
else if (mCurrentARIAMenubar) {
nsCOMPtr<nsIAccessibleEvent> menuEndEvent =
new nsAccEvent(nsIAccessibleEvent::EVENT_MENU_END, mCurrentARIAMenubar, PR_FALSE);
new nsAccEvent(nsIAccessibleEvent::EVENT_MENU_END, mCurrentARIAMenubar,
PR_FALSE, nsAccEvent::eAllowDupes);
if (menuEndEvent) {
FireDelayedAccessibleEvent(menuEndEvent, eAllowDupes);
FireDelayedAccessibleEvent(menuEndEvent);
}
mCurrentARIAMenubar = nsnull;
}
@ -539,7 +539,8 @@ return PR_FALSE;
}
FireDelayedToolkitEvent(nsIAccessibleEvent::EVENT_FOCUS,
finalFocusNode, eRemoveDupes, aIsAsynch);
finalFocusNode, nsAccEvent::eRemoveDupes,
aIsAsynch);
return PR_TRUE;
}

View File

@ -458,6 +458,10 @@ void nsHTMLSelectListAccessible::CacheChildren()
return;
}
if (mAccChildCount != eChildCountUninitialized) {
return;
}
mAccChildCount = 0; // Avoid reentry
PRInt32 childCount = 0;
nsCOMPtr<nsIAccessible> lastGoodAccessible =