Bug 563327 part 2. Drive accessibility events off the refresh driver instead of an ad-hoc timer. r=surkov

This commit is contained in:
Boris Zbarsky 2010-06-14 16:06:49 -04:00
Родитель 819ab2079d
Коммит 4658f4444e
2 изменённых файлов: 43 добавлений и 45 удалений

Просмотреть файл

@ -102,7 +102,7 @@ nsCOMPtr<nsINode> nsEventShell::sEventTargetNode;
////////////////////////////////////////////////////////////////////////////////
nsAccEventQueue::nsAccEventQueue(nsDocAccessible *aDocument):
mProcessingStarted(PR_FALSE), mDocument(aDocument), mFlushingEventsCount(0)
mObservingRefresh(PR_FALSE), mDocument(aDocument)
{
}
@ -157,6 +157,13 @@ nsAccEventQueue::Push(nsAccEvent *aEvent)
void
nsAccEventQueue::Shutdown()
{
if (mObservingRefresh) {
nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
if (!shell ||
shell->RemoveRefreshObserver(this, Flush_Display)) {
mObservingRefresh = PR_FALSE;
}
}
mDocument = nsnull;
mEvents.Clear();
}
@ -169,14 +176,19 @@ nsAccEventQueue::PrepareFlush()
{
// If there are pending events in the queue and events flush isn't planed
// yet start events flush asynchronously.
if (mEvents.Length() > 0 && !mProcessingStarted) {
NS_DISPATCH_RUNNABLEMETHOD(Flush, this)
mProcessingStarted = PR_TRUE;
if (mEvents.Length() > 0 && !mObservingRefresh) {
nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
// Use a Flush_Display observer so that it will get called after
// style and ayout have been flushed.
if (shell &&
shell->AddRefreshObserver(this, Flush_Display)) {
mObservingRefresh = PR_TRUE;
}
}
}
void
nsAccEventQueue::Flush()
nsAccEventQueue::WillRefresh(mozilla::TimeStamp aTime)
{
// If the document accessible is now shut down, don't fire events in it
// anymore.
@ -187,42 +199,31 @@ nsAccEventQueue::Flush()
if (!presShell)
return;
// Flush layout so that all the frame construction, reflow, and styles are
// up-to-date. This will ensure we can get frames for the related nodes, as
// well as get the most current information for calculating things like
// visibility. We don't flush the display because we don't care about
// painting. If no flush is necessary the method will simple return.
presShell->FlushPendingNotifications(Flush_Layout);
// Process only currently queued events. Newly appended events during events
// flushing won't be processed.
mFlushingEventsCount = mEvents.Length();
NS_ASSERTION(mFlushingEventsCount,
"How did we get here without events to fire?");
nsTArray < nsRefPtr<nsAccEvent> > events;
events.SwapElements(mEvents);
PRUint32 length = events.Length();
NS_ASSERTION(length, "How did we get here without events to fire?");
for (PRUint32 index = 0; index < mFlushingEventsCount; index ++) {
for (PRUint32 index = 0; index < length; index ++) {
// No presshell means the document was shut down during event handling
// by AT.
if (!mDocument || !mDocument->HasWeakShell())
break;
nsAccEvent *accEvent = mEvents[index];
nsAccEvent *accEvent = events[index];
if (accEvent->mEventRule != nsAccEvent::eDoNotEmit)
mDocument->ProcessPendingEvent(accEvent);
}
// Mark we are ready to start event processing again.
mProcessingStarted = PR_FALSE;
// If the document accessible is alive then remove processed events from the
// queue (otherwise they were removed on shutdown already) and reinitialize
// queue processing callback if necessary (new events might occur duiring
// delayed event processing).
if (mDocument && mDocument->HasWeakShell()) {
mEvents.RemoveElementsAt(0, mFlushingEventsCount);
mFlushingEventsCount = 0;
PrepareFlush();
if (mEvents.Length() == 0) {
nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
if (!shell ||
shell->RemoveRefreshObserver(this, Flush_Display)) {
mObservingRefresh = PR_FALSE;
}
}
}
@ -241,7 +242,7 @@ nsAccEventQueue::CoalesceEvents()
switch(tailEvent->mEventRule) {
case nsAccEvent::eCoalesceFromSameSubtree:
{
for (PRInt32 index = tail - 1; index >= mFlushingEventsCount; index--) {
for (PRInt32 index = tail - 1; index >= 0; index--) {
nsAccEvent* thisEvent = mEvents[index];
if (thisEvent->mEventType != tailEvent->mEventType)
@ -365,7 +366,7 @@ nsAccEventQueue::CoalesceEvents()
// Do not emit thisEvent, also apply this result to sibling nodes of
// thisNode.
thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
ApplyToSiblings(mFlushingEventsCount, index, thisEvent->mEventType,
ApplyToSiblings(0, index, thisEvent->mEventType,
thisEvent->mNode, nsAccEvent::eDoNotEmit);
continue;
}
@ -386,7 +387,7 @@ nsAccEventQueue::CoalesceEvents()
// Used for focus event, coalesce more older event since focus event
// for accessible can be duplicated by event for its document, we are
// interested in focus event for accessible.
for (PRInt32 index = tail - 1; index >= mFlushingEventsCount; index--) {
for (PRInt32 index = tail - 1; index >= 0; index--) {
nsAccEvent* thisEvent = mEvents[index];
if (thisEvent->mEventType == tailEvent->mEventType &&
thisEvent->mEventRule == tailEvent->mEventRule &&
@ -401,7 +402,7 @@ nsAccEventQueue::CoalesceEvents()
{
// Check for repeat events, coalesce newly appended event by more older
// event.
for (PRInt32 index = tail - 1; index >= mFlushingEventsCount; index--) {
for (PRInt32 index = tail - 1; index >= 0; index--) {
nsAccEvent* accEvent = mEvents[index];
if (accEvent->mEventType == tailEvent->mEventType &&
accEvent->mEventRule == tailEvent->mEventRule &&

Просмотреть файл

@ -45,6 +45,8 @@
#include "nsAutoPtr.h"
#include "nsRefreshDriver.h"
class nsIPersistentProperties;
/**
@ -90,7 +92,8 @@ private:
/**
* Event queue.
*/
class nsAccEventQueue : public nsISupports
class nsAccEventQueue : public nsISupports,
public nsARefreshObserver
{
public:
nsAccEventQueue(nsDocAccessible *aDocument);
@ -120,9 +123,7 @@ private:
* Process pending events. It calls nsDocAccessible::ProcessPendingEvent()
* where the real event processing is happen.
*/
void Flush();
NS_DECL_RUNNABLEMETHOD(nsAccEventQueue, Flush)
virtual void WillRefresh(mozilla::TimeStamp aTime);
/**
* Coalesce redundant events from the queue.
@ -157,9 +158,10 @@ private:
nsAccEvent *aDescendantAccEvent);
/**
* Indicates whether events flush is run.
* Indicates whether we're waiting on a refresh notification from our
* presshell to flush events
*/
PRBool mProcessingStarted;
PRBool mObservingRefresh;
/**
* The document accessible reference owning this queue.
@ -167,13 +169,8 @@ private:
nsRefPtr<nsDocAccessible> mDocument;
/**
* The number of events processed currently. Used to avoid event coalescence
* with new events appended to the queue because of events handling.
*/
PRInt32 mFlushingEventsCount;
/**
* Pending events array.
* Pending events array. Don't make this an nsAutoTArray; we use
* SwapElements() on it.
*/
nsTArray<nsRefPtr<nsAccEvent> > mEvents;
};