Bug 666446, Part 2/10 - Change nsRefreshDriver to accept imgIRequest objects to facilitate refresh driver-based animations. [r=roc]

This commit is contained in:
Scott Johnson 2011-11-01 11:06:53 -04:00
parent 4f4ae1dca2
commit f26c2d2f00
2 changed files with 96 additions and 2 deletions

View File

@ -114,6 +114,7 @@ nsRefreshDriver::nsRefreshDriver(nsPresContext *aPresContext)
mTimerIsPrecise(false), mTimerIsPrecise(false),
mLastTimerInterval(0) mLastTimerInterval(0)
{ {
mRequests.Init();
} }
nsRefreshDriver::~nsRefreshDriver() nsRefreshDriver::~nsRefreshDriver()
@ -185,6 +186,29 @@ nsRefreshDriver::RemoveRefreshObserver(nsARefreshObserver *aObserver,
return array.RemoveElement(aObserver); return array.RemoveElement(aObserver);
} }
bool
nsRefreshDriver::AddImageRequest(imgIRequest* aRequest)
{
if (!mRequests.PutEntry(aRequest)) {
return false;
}
EnsureTimerStarted(false);
return true;
}
void
nsRefreshDriver::RemoveImageRequest(imgIRequest* aRequest)
{
mRequests.RemoveEntry(aRequest);
}
void nsRefreshDriver::ClearAllImageRequests()
{
mRequests.Clear();
}
void void
nsRefreshDriver::EnsureTimerStarted(bool aAdjustingTimer) nsRefreshDriver::EnsureTimerStarted(bool aAdjustingTimer)
{ {
@ -238,6 +262,7 @@ nsRefreshDriver::ObserverCount() const
for (PRUint32 i = 0; i < ArrayLength(mObservers); ++i) { for (PRUint32 i = 0; i < ArrayLength(mObservers); ++i) {
sum += mObservers[i].Length(); sum += mObservers[i].Length();
} }
// Even while throttled, we need to process layout and style changes. Style // Even while throttled, we need to process layout and style changes. Style
// changes can trigger transitions which fire events when they complete, and // changes can trigger transitions which fire events when they complete, and
// layout changes can affect media queries on child documents, triggering // layout changes can affect media queries on child documents, triggering
@ -249,6 +274,12 @@ nsRefreshDriver::ObserverCount() const
return sum; return sum;
} }
PRUint32
nsRefreshDriver::ImageRequestCount() const
{
return mRequests.Count();
}
void void
nsRefreshDriver::UpdateMostRecentRefresh() nsRefreshDriver::UpdateMostRecentRefresh()
{ {
@ -303,7 +334,7 @@ nsRefreshDriver::Notify(nsITimer *aTimer)
UpdateMostRecentRefresh(); UpdateMostRecentRefresh();
nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell(); nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
if (!presShell || ObserverCount() == 0) { if (!presShell || (ObserverCount() == 0 && ImageRequestCount() == 0)) {
// Things are being destroyed, or we no longer have any observers. // Things are being destroyed, or we no longer have any observers.
// We don't want to stop the timer when observers are initially // We don't want to stop the timer when observers are initially
// removed, because sometimes observers can be added and removed // removed, because sometimes observers can be added and removed
@ -332,6 +363,7 @@ nsRefreshDriver::Notify(nsITimer *aTimer)
return NS_OK; return NS_OK;
} }
} }
if (i == 0) { if (i == 0) {
// Don't just loop while we have things in mBeforePaintTargets, // Don't just loop while we have things in mBeforePaintTargets,
// the whole point is that event handlers should readd the // the whole point is that event handlers should readd the
@ -404,6 +436,17 @@ nsRefreshDriver::Notify(nsITimer *aTimer)
} }
} }
/*
* Perform notification to imgIRequests subscribed to listen
* for refresh events.
*/
ImageRequestParameters parms = {mMostRecentRefresh};
if (mRequests.Count()) {
mRequests.EnumerateEntries(nsRefreshDriver::ImageRequestEnumerator, &parms);
EnsureTimerStarted(false);
}
if (mThrottled || if (mThrottled ||
(mTimerIsPrecise != (mTimerIsPrecise !=
(GetRefreshTimerType() == nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP))) { (GetRefreshTimerType() == nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP))) {
@ -424,6 +467,24 @@ nsRefreshDriver::Notify(nsITimer *aTimer)
return NS_OK; return NS_OK;
} }
PLDHashOperator
nsRefreshDriver::ImageRequestEnumerator(nsISupportsHashKey* aEntry,
void* aUserArg)
{
ImageRequestParameters* parms =
static_cast<ImageRequestParameters*> (aUserArg);
mozilla::TimeStamp mostRecentRefresh = parms->ts;
imgIRequest* req = static_cast<imgIRequest*>(aEntry->GetKey());
NS_ABORT_IF_FALSE(req, "Unable to retrieve the image request");
nsCOMPtr<imgIContainer> image;
req->GetImage(getter_AddRefs(image));
if (image) {
image->RequestRefresh(mostRecentRefresh);
}
return PL_DHASH_NEXT;
}
void void
nsRefreshDriver::Freeze() nsRefreshDriver::Freeze()
{ {
@ -437,7 +498,7 @@ nsRefreshDriver::Thaw()
{ {
NS_ASSERTION(mFrozen, "Thaw called on an unfrozen refresh driver"); NS_ASSERTION(mFrozen, "Thaw called on an unfrozen refresh driver");
mFrozen = false; mFrozen = false;
if (ObserverCount()) { if (ObserverCount() || ImageRequestCount()) {
// FIXME: This isn't quite right, since our EnsureTimerStarted call // FIXME: This isn't quite right, since our EnsureTimerStarted call
// updates our mMostRecentRefresh, but the DoRefresh call won't run // updates our mMostRecentRefresh, but the DoRefresh call won't run
// and notify our observers until we get back to the event loop. // and notify our observers until we get back to the event loop.

View File

@ -50,10 +50,13 @@
#include "nsTObserverArray.h" #include "nsTObserverArray.h"
#include "nsTArray.h" #include "nsTArray.h"
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "nsTHashtable.h"
#include "nsHashKeys.h"
class nsPresContext; class nsPresContext;
class nsIPresShell; class nsIPresShell;
class nsIDocument; class nsIDocument;
class imgIRequest;
/** /**
* An abstract base class to be implemented by callers wanting to be * An abstract base class to be implemented by callers wanting to be
@ -128,6 +131,24 @@ public:
bool RemoveRefreshObserver(nsARefreshObserver *aObserver, bool RemoveRefreshObserver(nsARefreshObserver *aObserver,
mozFlushType aFlushType); mozFlushType aFlushType);
/**
* Add/Remove imgIRequest versions of observers.
*
* These are used for hooking into the refresh driver for
* controlling animated images.
*
* @note The refresh driver owns a reference to these listeners.
*
* @note Technically, imgIRequest objects are not nsARefreshObservers, but
* for controlling animated image repaint events, we subscribe the
* imgIRequests to the nsRefreshDriver for notification of paint events.
*
* @returns whether the operation succeeded, or void in the case of removal.
*/
bool AddImageRequest(imgIRequest* aRequest);
void RemoveImageRequest(imgIRequest* aRequest);
void ClearAllImageRequests();
/** /**
* Add / remove presshells that we should flush style and layout on * Add / remove presshells that we should flush style and layout on
*/ */
@ -218,10 +239,15 @@ public:
private: private:
typedef nsTObserverArray<nsARefreshObserver*> ObserverArray; typedef nsTObserverArray<nsARefreshObserver*> ObserverArray;
typedef nsTHashtable<nsISupportsHashKey> RequestTable;
void EnsureTimerStarted(bool aAdjustingTimer); void EnsureTimerStarted(bool aAdjustingTimer);
void StopTimer(); void StopTimer();
PRUint32 ObserverCount() const; PRUint32 ObserverCount() const;
PRUint32 ImageRequestCount() const;
static PLDHashOperator ImageRequestEnumerator(nsISupportsHashKey* aEntry,
void* aUserArg);
void UpdateMostRecentRefresh(); void UpdateMostRecentRefresh();
ObserverArray& ArrayFor(mozFlushType aFlushType); ObserverArray& ArrayFor(mozFlushType aFlushType);
// Trigger a refresh immediately, if haven't been disconnected or frozen. // Trigger a refresh immediately, if haven't been disconnected or frozen.
@ -252,6 +278,8 @@ private:
// separate arrays for each flush type we support // separate arrays for each flush type we support
ObserverArray mObservers[3]; ObserverArray mObservers[3];
RequestTable mRequests;
nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers; nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers;
nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers; nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers;
// nsTArray on purpose, because we want to be able to swap. // nsTArray on purpose, because we want to be able to swap.
@ -262,6 +290,11 @@ private:
// This is the last interval we used for our timer. May be 0 if we // This is the last interval we used for our timer. May be 0 if we
// haven't computed a timer interval yet. // haven't computed a timer interval yet.
mutable PRInt32 mLastTimerInterval; mutable PRInt32 mLastTimerInterval;
// Helper struct for processing image requests
struct ImageRequestParameters {
mozilla::TimeStamp ts;
};
}; };
#endif /* !defined(nsRefreshDriver_h_) */ #endif /* !defined(nsRefreshDriver_h_) */