зеркало из 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):
|
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;
|
||||||
};
|
};
|
||||||
|
|
Загрузка…
Ссылка в новой задаче