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): 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 void
nsAccEventQueue::Shutdown() nsAccEventQueue::Shutdown()
{ {
if (mObservingRefresh) {
nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
if (!shell ||
shell->RemoveRefreshObserver(this, Flush_Display)) {
mObservingRefresh = PR_FALSE;
}
}
mDocument = nsnull; mDocument = nsnull;
mEvents.Clear(); mEvents.Clear();
} }
@ -169,14 +176,19 @@ nsAccEventQueue::PrepareFlush()
{ {
// If there are pending events in the queue and events flush isn't planed // If there are pending events in the queue and events flush isn't planed
// yet start events flush asynchronously. // yet start events flush asynchronously.
if (mEvents.Length() > 0 && !mProcessingStarted) { if (mEvents.Length() > 0 && !mObservingRefresh) {
NS_DISPATCH_RUNNABLEMETHOD(Flush, this) nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
mProcessingStarted = PR_TRUE; // 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 void
nsAccEventQueue::Flush() nsAccEventQueue::WillRefresh(mozilla::TimeStamp aTime)
{ {
// If the document accessible is now shut down, don't fire events in it // If the document accessible is now shut down, don't fire events in it
// anymore. // anymore.
@ -187,42 +199,31 @@ nsAccEventQueue::Flush()
if (!presShell) if (!presShell)
return; 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 // Process only currently queued events. Newly appended events during events
// flushing won't be processed. // flushing won't be processed.
mFlushingEventsCount = mEvents.Length(); nsTArray < nsRefPtr<nsAccEvent> > events;
NS_ASSERTION(mFlushingEventsCount, events.SwapElements(mEvents);
"How did we get here without events to fire?"); 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 // No presshell means the document was shut down during event handling
// by AT. // by AT.
if (!mDocument || !mDocument->HasWeakShell()) if (!mDocument || !mDocument->HasWeakShell())
break; break;
nsAccEvent *accEvent = mEvents[index]; nsAccEvent *accEvent = events[index];
if (accEvent->mEventRule != nsAccEvent::eDoNotEmit) if (accEvent->mEventRule != nsAccEvent::eDoNotEmit)
mDocument->ProcessPendingEvent(accEvent); mDocument->ProcessPendingEvent(accEvent);
} }
// Mark we are ready to start event processing again. if (mEvents.Length() == 0) {
mProcessingStarted = PR_FALSE; nsCOMPtr<nsIPresShell> shell = mDocument->GetPresShell();
if (!shell ||
// If the document accessible is alive then remove processed events from the shell->RemoveRefreshObserver(this, Flush_Display)) {
// queue (otherwise they were removed on shutdown already) and reinitialize mObservingRefresh = PR_FALSE;
// queue processing callback if necessary (new events might occur duiring }
// delayed event processing).
if (mDocument && mDocument->HasWeakShell()) {
mEvents.RemoveElementsAt(0, mFlushingEventsCount);
mFlushingEventsCount = 0;
PrepareFlush();
} }
} }
@ -241,7 +242,7 @@ nsAccEventQueue::CoalesceEvents()
switch(tailEvent->mEventRule) { switch(tailEvent->mEventRule) {
case nsAccEvent::eCoalesceFromSameSubtree: case nsAccEvent::eCoalesceFromSameSubtree:
{ {
for (PRInt32 index = tail - 1; index >= mFlushingEventsCount; index--) { for (PRInt32 index = tail - 1; index >= 0; index--) {
nsAccEvent* thisEvent = mEvents[index]; nsAccEvent* thisEvent = mEvents[index];
if (thisEvent->mEventType != tailEvent->mEventType) if (thisEvent->mEventType != tailEvent->mEventType)
@ -365,7 +366,7 @@ nsAccEventQueue::CoalesceEvents()
// Do not emit thisEvent, also apply this result to sibling nodes of // Do not emit thisEvent, also apply this result to sibling nodes of
// thisNode. // thisNode.
thisEvent->mEventRule = nsAccEvent::eDoNotEmit; thisEvent->mEventRule = nsAccEvent::eDoNotEmit;
ApplyToSiblings(mFlushingEventsCount, index, thisEvent->mEventType, ApplyToSiblings(0, index, thisEvent->mEventType,
thisEvent->mNode, nsAccEvent::eDoNotEmit); thisEvent->mNode, nsAccEvent::eDoNotEmit);
continue; continue;
} }
@ -386,7 +387,7 @@ nsAccEventQueue::CoalesceEvents()
// Used for focus event, coalesce more older event since focus event // Used for focus event, coalesce more older event since focus event
// for accessible can be duplicated by event for its document, we are // for accessible can be duplicated by event for its document, we are
// interested in focus event for accessible. // 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]; nsAccEvent* thisEvent = mEvents[index];
if (thisEvent->mEventType == tailEvent->mEventType && if (thisEvent->mEventType == tailEvent->mEventType &&
thisEvent->mEventRule == tailEvent->mEventRule && thisEvent->mEventRule == tailEvent->mEventRule &&
@ -401,7 +402,7 @@ nsAccEventQueue::CoalesceEvents()
{ {
// Check for repeat events, coalesce newly appended event by more older // Check for repeat events, coalesce newly appended event by more older
// event. // event.
for (PRInt32 index = tail - 1; index >= mFlushingEventsCount; index--) { for (PRInt32 index = tail - 1; index >= 0; index--) {
nsAccEvent* accEvent = mEvents[index]; nsAccEvent* accEvent = mEvents[index];
if (accEvent->mEventType == tailEvent->mEventType && if (accEvent->mEventType == tailEvent->mEventType &&
accEvent->mEventRule == tailEvent->mEventRule && accEvent->mEventRule == tailEvent->mEventRule &&

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

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