зеркало из https://github.com/mozilla/gecko-dev.git
Bug 563327 part 2. Drive accessibility events off the refresh driver instead of an ad-hoc timer. r=surkov
This commit is contained in:
Родитель
819ab2079d
Коммит
4658f4444e
|
@ -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;
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче