Bug 415069 ARIA alerts triggering events with :system p=aaronleventhal r=ginn.chen a=mtschrep

This commit is contained in:
ginn.chen@sun.com 2008-02-19 03:22:01 -08:00
parent 66d44fb0ab
commit 8fe3f39df3
6 changed files with 54 additions and 39 deletions

View File

@ -61,7 +61,7 @@ interface nsIDOMNode;
*
* @status UNDER_REVIEW
*/
[scriptable, uuid(98f9e2d4-ec22-4601-b927-b9faf7a63248)]
[scriptable, uuid(ba448f0e-a761-48c8-a0f5-1f25e23d4fe4)]
interface nsIAccessibleEvent : nsISupports
{
/**
@ -511,7 +511,7 @@ interface nsIAccessibleEvent : nsISupports
* Returns true if the event was caused by explicit user input,
* as opposed to purely originating from a timer or mouse movement
*/
readonly attribute boolean isFromUserInput;
attribute boolean isFromUserInput;
};

View File

@ -95,14 +95,14 @@ void nsAccEvent::CaptureIsFromUserInput(PRBool aIsAsynch)
return;
}
if (aIsAsynch) {
// Cannot calculate, so use previous value
gLastEventNodeWeak = eventNode;
}
else {
if (!aIsAsynch) {
PrepareForEvent(eventNode);
mIsFromUserInput = gLastEventFromUserInput;
}
// For asynch, cannot calculate if from user input.
// Don't reset global last input state here, do it
// at the end of FlushPendingEvents()
mIsFromUserInput = gLastEventFromUserInput;
}
@ -113,13 +113,30 @@ nsAccEvent::GetIsFromUserInput(PRBool *aIsFromUserInput)
return NS_OK;
}
void nsAccEvent::PrepareForEvent(nsIAccessibleEvent *aEvent)
NS_IMETHODIMP
nsAccEvent::SetIsFromUserInput(PRBool aIsFromUserInput)
{
mIsFromUserInput = aIsFromUserInput;
return NS_OK;
}
void nsAccEvent::PrepareForEvent(nsIAccessibleEvent *aEvent,
PRBool aForceIsFromUserInput)
{
gLastEventFromUserInput = aForceIsFromUserInput;
nsCOMPtr<nsIDOMNode> eventNode;
aEvent->GetDOMNode(getter_AddRefs(eventNode));
PRBool isFromUserInput;
aEvent->GetIsFromUserInput(&isFromUserInput);
PrepareForEvent(eventNode, isFromUserInput);
if (!gLastEventFromUserInput) { // Caller is not forcing user input flag
aEvent->GetIsFromUserInput(&gLastEventFromUserInput);
if (!gLastEventFromUserInput) {
// Event does not have user input flag set to true
// One more try -- check to see if we are currently responding to user input
PrepareForEvent(eventNode);
}
}
gLastEventNodeWeak = eventNode;
// Make sure this event remembers whether it is from user input
aEvent->SetIsFromUserInput(gLastEventFromUserInput);
}
void nsAccEvent::PrepareForEvent(nsIDOMNode *aEventNode,
@ -154,7 +171,7 @@ void nsAccEvent::PrepareForEvent(nsIDOMNode *aEventNode,
nsIEventStateManager *esm = presShell->GetPresContext()->EventStateManager();
if (!esm) {
NS_NOTREACHED("Threre should always be an ESM for an event");
NS_NOTREACHED("There should always be an ESM for an event");
return;
}

View File

@ -81,11 +81,17 @@ private:
static nsIDOMNode* gLastEventNodeWeak;
public:
static void ResetLastInputState()
{gLastEventFromUserInput = PR_FALSE; gLastEventNodeWeak = nsnull; }
/**
* Find and cache the last input state. This will be called automatically
* for synchronous events. For asynchronous events it should be
* called from the synchronous code which is the true source of the event,
* before the event is fired.
* @param aChangeNode that event will be on
* @param aForceIsFromUserInput PR_TRUE if the caller knows that this event was
* caused by user input
*/
static void PrepareForEvent(nsIDOMNode *aChangeNode,
PRBool aForceIsFromUserInput = PR_FALSE);
@ -95,7 +101,8 @@ public:
* so use that state now -- call this when about to flush an event that
* was waiting in an event queue
*/
static void PrepareForEvent(nsIAccessibleEvent *aEvent);
static void PrepareForEvent(nsIAccessibleEvent *aEvent,
PRBool aForceIsFromUserInput = PR_FALSE);
};
class nsAccStateChangeEvent: public nsAccEvent,

View File

@ -1389,16 +1389,15 @@ nsresult nsDocAccessible::FireDelayedToolkitEvent(PRUint32 aEvent,
PRBool aIsAsynch)
{
nsCOMPtr<nsIAccessibleEvent> event =
new nsAccEvent(aEvent, aDOMNode, PR_TRUE);
new nsAccEvent(aEvent, aDOMNode, aIsAsynch);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
return FireDelayedAccessibleEvent(event, aAllowDupes, aIsAsynch);
return FireDelayedAccessibleEvent(event, aAllowDupes);
}
nsresult
nsDocAccessible::FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent,
EDupeEventRule aAllowDupes,
PRBool aIsAsynch)
EDupeEventRule aAllowDupes)
{
NS_ENSURE_TRUE(aEvent, NS_ERROR_FAILURE);
@ -1416,13 +1415,6 @@ nsDocAccessible::FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent,
nsCOMPtr<nsIDOMNode> newEventDOMNode;
aEvent->GetDOMNode(getter_AddRefs(newEventDOMNode));
if (!aIsAsynch) {
// If already asynchronous don't call PrepareFromEvent() -- it
// should only be called while ESM still knows if the event occurred
// originally because of user input
nsAccEvent::PrepareForEvent(newEventDOMNode);
}
if (numQueuedEvents == 0) {
isTimerStarted = PR_FALSE;
} else if (aAllowDupes == eCoalesceFromSameSubtree) {
@ -1566,9 +1558,7 @@ NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
nsCOMPtr<nsIAccessibleTextChangeEvent> textChangeEvent =
CreateTextChangeEventForNode(containerAccessible, domNode, accessible, PR_TRUE, PR_TRUE);
if (textChangeEvent) {
nsCOMPtr<nsIDOMNode> hyperTextNode;
textChangeEvent->GetDOMNode(getter_AddRefs(hyperTextNode));
nsAccEvent::PrepareForEvent(hyperTextNode, isFromUserInput);
nsAccEvent::PrepareForEvent(textChangeEvent, isFromUserInput);
// XXX Queue them up and merge the text change events
// XXX We need a way to ignore SplitNode and JoinNode() when they
// do not affect the text within the hypertext
@ -1640,6 +1630,10 @@ NS_IMETHODIMP nsDocAccessible::FlushPendingEvents()
}
mEventsToFire.Clear(); // Clear out array
NS_RELEASE_THIS(); // Release kung fu death grip
// After a flood of events, reset so that user input flag is off
nsAccEvent::ResetLastInputState();
return NS_OK;
}
@ -1964,9 +1958,9 @@ 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, PR_TRUE);
new nsAccEvent(nsIAccessibleEvent::EVENT_REORDER, containerAccessible, isAsynch);
NS_ENSURE_TRUE(reorderEvent, NS_ERROR_OUT_OF_MEMORY);
FireDelayedAccessibleEvent(reorderEvent, eCoalesceFromSameSubtree, isAsynch);
FireDelayedAccessibleEvent(reorderEvent, eCoalesceFromSameSubtree);
}
}
@ -2045,10 +2039,10 @@ nsDocAccessible::FireShowHideEvents(nsIDOMNode *aDOMNode, PRBool aAvoidOnThisNod
new nsAccEvent(aEventType, accessible, isAsynch);
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
if (aForceIsFromUserInput) {
nsAccEvent::PrepareForEvent(aDOMNode, aForceIsFromUserInput);
nsAccEvent::PrepareForEvent(event, aForceIsFromUserInput);
}
if (aDelay) {
return FireDelayedAccessibleEvent(event, eCoalesceFromSameSubtree, isAsynch);
return FireDelayedAccessibleEvent(event, eCoalesceFromSameSubtree);
}
return FireAccessibleEvent(event);
}

View File

@ -114,8 +114,8 @@ class nsDocAccessible : public nsHyperTextAccessibleWrap,
* eRemoveDupes (default): events of the same type are discarded
* (the last one is used)
*
* @param aIsAsyn - set to PR_TRUE if this is not being called from code
* synchronous with a DOM event
* @param aIsAsynch - set to PR_TRUE if this is not being called from code
* synchronous with a DOM event
*/
nsresult FireDelayedToolkitEvent(PRUint32 aEvent, nsIDOMNode *aDOMNode,
EDupeEventRule aAllowDupes = eRemoveDupes,
@ -128,12 +128,9 @@ class nsDocAccessible : public nsHyperTextAccessibleWrap,
* @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.
* @param aIsAsych - set to PR_TRUE if this is being called from
* an event asynchronous with the DOM
*/
nsresult FireDelayedAccessibleEvent(nsIAccessibleEvent *aEvent,
EDupeEventRule aAllowDupes = eRemoveDupes,
PRBool aIsAsynch = PR_FALSE);
EDupeEventRule aAllowDupes = eRemoveDupes);
void ShutdownChildDocuments(nsIDocShellTreeItem *aStart);

View File

@ -519,7 +519,7 @@ PRBool nsRootAccessible::FireAccessibleFocusEvent(nsIAccessible *aAccessible,
nsCOMPtr<nsIAccessibleEvent> menuEndEvent =
new nsAccEvent(nsIAccessibleEvent::EVENT_MENU_END, mCurrentARIAMenubar, PR_FALSE);
if (menuEndEvent) {
FireDelayedAccessibleEvent(menuEndEvent, eAllowDupes, PR_FALSE);
FireDelayedAccessibleEvent(menuEndEvent, eAllowDupes);
}
mCurrentARIAMenubar = nsnull;
}