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 2357006c95
commit c3b8c9baa6
2 changed files with 96 additions and 2 deletions

View File

@ -114,6 +114,7 @@ nsRefreshDriver::nsRefreshDriver(nsPresContext *aPresContext)
mTimerIsPrecise(false),
mLastTimerInterval(0)
{
mRequests.Init();
}
nsRefreshDriver::~nsRefreshDriver()
@ -185,6 +186,29 @@ nsRefreshDriver::RemoveRefreshObserver(nsARefreshObserver *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
nsRefreshDriver::EnsureTimerStarted(bool aAdjustingTimer)
{
@ -238,6 +262,7 @@ nsRefreshDriver::ObserverCount() const
for (PRUint32 i = 0; i < ArrayLength(mObservers); ++i) {
sum += mObservers[i].Length();
}
// Even while throttled, we need to process layout and style changes. Style
// changes can trigger transitions which fire events when they complete, and
// layout changes can affect media queries on child documents, triggering
@ -249,6 +274,12 @@ nsRefreshDriver::ObserverCount() const
return sum;
}
PRUint32
nsRefreshDriver::ImageRequestCount() const
{
return mRequests.Count();
}
void
nsRefreshDriver::UpdateMostRecentRefresh()
{
@ -303,7 +334,7 @@ nsRefreshDriver::Notify(nsITimer *aTimer)
UpdateMostRecentRefresh();
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.
// We don't want to stop the timer when observers are initially
// removed, because sometimes observers can be added and removed
@ -332,6 +363,7 @@ nsRefreshDriver::Notify(nsITimer *aTimer)
return NS_OK;
}
}
if (i == 0) {
// Don't just loop while we have things in mBeforePaintTargets,
// 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 ||
(mTimerIsPrecise !=
(GetRefreshTimerType() == nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP))) {
@ -424,6 +467,24 @@ nsRefreshDriver::Notify(nsITimer *aTimer)
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
nsRefreshDriver::Freeze()
{
@ -437,7 +498,7 @@ nsRefreshDriver::Thaw()
{
NS_ASSERTION(mFrozen, "Thaw called on an unfrozen refresh driver");
mFrozen = false;
if (ObserverCount()) {
if (ObserverCount() || ImageRequestCount()) {
// FIXME: This isn't quite right, since our EnsureTimerStarted call
// updates our mMostRecentRefresh, but the DoRefresh call won't run
// and notify our observers until we get back to the event loop.

View File

@ -50,10 +50,13 @@
#include "nsTObserverArray.h"
#include "nsTArray.h"
#include "nsAutoPtr.h"
#include "nsTHashtable.h"
#include "nsHashKeys.h"
class nsPresContext;
class nsIPresShell;
class nsIDocument;
class imgIRequest;
/**
* An abstract base class to be implemented by callers wanting to be
@ -128,6 +131,24 @@ public:
bool RemoveRefreshObserver(nsARefreshObserver *aObserver,
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
*/
@ -218,10 +239,15 @@ public:
private:
typedef nsTObserverArray<nsARefreshObserver*> ObserverArray;
typedef nsTHashtable<nsISupportsHashKey> RequestTable;
void EnsureTimerStarted(bool aAdjustingTimer);
void StopTimer();
PRUint32 ObserverCount() const;
PRUint32 ImageRequestCount() const;
static PLDHashOperator ImageRequestEnumerator(nsISupportsHashKey* aEntry,
void* aUserArg);
void UpdateMostRecentRefresh();
ObserverArray& ArrayFor(mozFlushType aFlushType);
// Trigger a refresh immediately, if haven't been disconnected or frozen.
@ -252,6 +278,8 @@ private:
// separate arrays for each flush type we support
ObserverArray mObservers[3];
RequestTable mRequests;
nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers;
nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers;
// 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
// haven't computed a timer interval yet.
mutable PRInt32 mLastTimerInterval;
// Helper struct for processing image requests
struct ImageRequestParameters {
mozilla::TimeStamp ts;
};
};
#endif /* !defined(nsRefreshDriver_h_) */