diff --git a/mozilla/accessible/src/base/nsAccessibilityUtils.cpp b/mozilla/accessible/src/base/nsAccessibilityUtils.cpp index c43ecf573f2..445730fd08f 100755 --- a/mozilla/accessible/src/base/nsAccessibilityUtils.cpp +++ b/mozilla/accessible/src/base/nsAccessibilityUtils.cpp @@ -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 loopNode = aPossibleDescendantNode; nsCOMPtr 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 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 nsAccUtils::GetAncestorWithRole(nsIAccessible *aDescendant, PRUint32 aRole) { diff --git a/mozilla/accessible/src/base/nsAccessibilityUtils.h b/mozilla/accessible/src/base/nsAccessibilityUtils.h index 4ac7421675d..9672fbf42a2 100755 --- a/mozilla/accessible/src/base/nsAccessibilityUtils.h +++ b/mozilla/accessible/src/base/nsAccessibilityUtils.h @@ -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 diff --git a/mozilla/accessible/src/base/nsAccessibleEventData.cpp b/mozilla/accessible/src/base/nsAccessibleEventData.cpp index 2178e0a85ca..401d5f9cc83 100755 --- a/mozilla/accessible/src/base/nsAccessibleEventData.cpp +++ b/mozilla/accessible/src/base/nsAccessibleEventData.cpp @@ -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 &aEventsToFire) +{ + PRUint32 numQueuedEvents = aEventsToFire.Count(); + for (PRInt32 tail = numQueuedEvents - 1; tail >= 0; tail --) { + nsRefPtr tailEvent = GetAccEventPtr(aEventsToFire[tail]); + switch(tailEvent->mEventRule) { + case nsAccEvent::eCoalesceFromSameSubtree: + { + for (PRInt32 index = 0; index < tail; index ++) { + nsRefPtr 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 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 &aEventsToFire, + PRUint32 aStart, PRUint32 aEnd, + PRUint32 aEventType, nsIDOMNode* aDOMNode, + EEventRule aEventRule) +{ + for (PRUint32 index = aStart; index < aEnd; index ++) { + nsRefPtr 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, diff --git a/mozilla/accessible/src/base/nsAccessibleEventData.h b/mozilla/accessible/src/base/nsAccessibleEventData.h index ce2909f910b..ef11872c589 100644 --- a/mozilla/accessible/src/base/nsAccessibleEventData.h +++ b/mozilla/accessible/src/base/nsAccessibleEventData.h @@ -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 mAccessible; nsCOMPtr mDOMNode; nsCOMPtr 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 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 &aEventsToFire); + +private: + static already_AddRefed 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 &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 { diff --git a/mozilla/accessible/src/base/nsCaretAccessible.cpp b/mozilla/accessible/src/base/nsCaretAccessible.cpp index 4a734571d91..c419bb65ef0 100644 --- a/mozilla/accessible/src/base/nsCaretAccessible.cpp +++ b/mozilla/accessible/src/base/nsCaretAccessible.cpp @@ -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 diff --git a/mozilla/accessible/src/base/nsDocAccessible.cpp b/mozilla/accessible/src/base/nsDocAccessible.cpp index c10abf629b0..eee97f10cb4 100644 --- a/mozilla/accessible/src/base/nsDocAccessible.cpp +++ b/mozilla/accessible/src/base/nsDocAccessible.cpp @@ -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 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 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 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 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 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 accessibleEvent( do_QueryInterface(mEventsToFire[index])); - NS_ASSERTION(accessibleEvent, "Array item is not an accessible event"); + + if (nsAccEvent::EventRule(accessibleEvent) == nsAccEvent::eDoNotEmit) + continue; nsCOMPtr accessible; accessibleEvent->GetAccessible(getter_AddRefs(accessible)); nsCOMPtr 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 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 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 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); } diff --git a/mozilla/accessible/src/base/nsDocAccessible.h b/mozilla/accessible/src/base/nsDocAccessible.h index b4330a31cac..27b58696b42 100644 --- a/mozilla/accessible/src/base/nsDocAccessible.h +++ b/mozilla/accessible/src/base/nsDocAccessible.h @@ -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); diff --git a/mozilla/accessible/src/base/nsRootAccessible.cpp b/mozilla/accessible/src/base/nsRootAccessible.cpp index 8123e2c7ad5..97d8d6df920 100644 --- a/mozilla/accessible/src/base/nsRootAccessible.cpp +++ b/mozilla/accessible/src/base/nsRootAccessible.cpp @@ -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 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; } diff --git a/mozilla/accessible/src/html/nsHTMLSelectAccessible.cpp b/mozilla/accessible/src/html/nsHTMLSelectAccessible.cpp index c1191111f09..03ad927ad99 100644 --- a/mozilla/accessible/src/html/nsHTMLSelectAccessible.cpp +++ b/mozilla/accessible/src/html/nsHTMLSelectAccessible.cpp @@ -458,6 +458,10 @@ void nsHTMLSelectListAccessible::CacheChildren() return; } + if (mAccChildCount != eChildCountUninitialized) { + return; + } + mAccChildCount = 0; // Avoid reentry PRInt32 childCount = 0; nsCOMPtr lastGoodAccessible =