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:
parent
6a890a5336
commit
e9a234c845
@ -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)
|
||||
{
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -458,6 +458,10 @@ void nsHTMLSelectListAccessible::CacheChildren()
|
||||
return;
|
||||
}
|
||||
|
||||
if (mAccChildCount != eChildCountUninitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
mAccChildCount = 0; // Avoid reentry
|
||||
PRInt32 childCount = 0;
|
||||
nsCOMPtr<nsIAccessible> lastGoodAccessible =
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user