Make nsRefreshDriver reference-counted instead of being a sub-object of the pres context. (
Bug 531585) r=bzbarsky
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -254,16 +254,20 @@ nsPresContext::nsPresContext(nsIDocument
nsPresContext::~nsPresContext()
{
for (PRUint32 i = 0; i < IMAGE_LOAD_TYPE_COUNT; ++i)
mImageLoaders[i].Enumerate(destroy_loads, nsnull);
NS_PRECONDITION(!mShell, "Presshell forgot to clear our mShell pointer");
SetShell(nsnull);
+ if (mRefreshDriver) {
+ mRefreshDriver->Disconnect();
+ }
+
delete mTransitionManager;
if (mEventManager) {
// unclear if these are needed, but can't hurt
mEventManager->NotifyDestroyPresContext(this);
mEventManager->SetPresContext(nsnull);
NS_RELEASE(mEventManager);
@@ -868,16 +872,22 @@ nsPresContext::Init(nsIDeviceContext* aD
mEventManager = new nsEventStateManager();
if (!mEventManager)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(mEventManager);
mTransitionManager = new nsTransitionManager(this);
+ if (!mTransitionManager)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ mRefreshDriver = new nsRefreshDriver(this);
+ if (!mRefreshDriver)
+ return NS_ERROR_OUT_OF_MEMORY;
mLangService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
// Register callbacks so we're notified when the preferences change
nsContentUtils::RegisterPrefCallback("font.",
nsPresContext::PrefChangedCallback,
this);
nsContentUtils::RegisterPrefCallback("browser.display.",
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -67,17 +67,16 @@
#include "gfxRect.h"
#include "nsRegion.h"
#include "nsTArray.h"
#include "nsAutoPtr.h"
#include "nsThreadUtils.h"
#include "nsContentUtils.h"
#include "nsIWidget.h"
#include "mozilla/TimeStamp.h"
-#include "nsRefreshDriver.h"
class nsImageLoader;
#ifdef IBMBIDI
class nsBidiPresUtils;
#endif // IBMBIDI
struct nsRect;
@@ -98,16 +97,17 @@ class nsIAtom;
struct nsStyleBackground;
struct nsStyleBorder;
class nsIRunnable;
class gfxUserFontSet;
class nsUserFontSet;
struct nsFontFaceRuleContainer;
class nsObjectFrame;
class nsTransitionManager;
+class nsRefreshDriver;
class imgIContainer;
#ifdef MOZ_REFLOW_PERF
class nsIRenderingContext;
#endif
enum nsWidgetType {
eWidgetType_Button = 1,
@@ -228,23 +228,17 @@ public:
#ifdef _IMPL_NS_LAYOUT
nsStyleSet* StyleSet() { return GetPresShell()->StyleSet(); }
nsFrameManager* FrameManager()
{ return GetPresShell()->FrameManager(); }
nsTransitionManager* TransitionManager() { return mTransitionManager; }
- nsRefreshDriver* RefreshDriver() { return &mRefreshDriver; }
-
- static nsPresContext* FromRefreshDriver(nsRefreshDriver* aRefreshDriver) {
- return reinterpret_cast<nsPresContext*>(
- reinterpret_cast<char*>(aRefreshDriver) -
- offsetof(nsPresContext, mRefreshDriver));
- }
+ nsRefreshDriver* RefreshDriver() { return mRefreshDriver; }
#endif
/**
* Rebuilds all style data by throwing out the old rule tree and
* building a new one, and additionally applying aExtraHint (which
* must not contain nsChangeHint_ReconstructFrame) to the root frame.
* Also rebuild the user font set.
*/
@@ -952,17 +946,17 @@ protected:
nsCOMPtr<nsIDocument> mDocument;
nsIDeviceContext* mDeviceContext; // [STRONG] could be weak, but
// better safe than sorry.
// Cannot reintroduce cycles
// since there is no dependency
// from gfx back to layout.
nsIEventStateManager* mEventManager; // [STRONG]
nsILookAndFeel* mLookAndFeel; // [STRONG]
- nsRefreshDriver mRefreshDriver;
+ nsRefPtr<nsRefreshDriver> mRefreshDriver;
nsTransitionManager* mTransitionManager; // owns; it aggregates our refcount
nsIAtom* mMedium; // initialized by subclass ctors;
// weak pointer to static atom
nsILinkHandler* mLinkHandler; // [WEAK]
nsIAtom* mLangGroup; // [STRONG]
nsRefPtrHashtable<nsVoidPtrHashKey, nsImageLoader>
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -51,17 +51,18 @@
* is not visible, we need to hook it up to FlushPendingNotifications so
* that we flush when necessary.
*/
#define REFRESH_INTERVAL_MILLISECONDS 20
using mozilla::TimeStamp;
-nsRefreshDriver::nsRefreshDriver()
+nsRefreshDriver::nsRefreshDriver(nsPresContext *aPresContext)
+ : mPresContext(aPresContext)
{
}
nsRefreshDriver::~nsRefreshDriver()
{
NS_ABORT_IF_FALSE(ObserverCount() == 0,
"observers should have unregistered");
NS_ABORT_IF_FALSE(!mTimer, "timer should be gone");
@@ -165,33 +166,33 @@ nsRefreshDriver::ArrayFor(mozFlushType a
return *static_cast<ObserverArray*>(nsnull);
}
}
/*
* nsISupports implementation
*/
-NS_IMPL_ADDREF_USING_AGGREGATOR(nsRefreshDriver,
- nsPresContext::FromRefreshDriver(this))
-NS_IMPL_RELEASE_USING_AGGREGATOR(nsRefreshDriver,
- nsPresContext::FromRefreshDriver(this))
-NS_IMPL_QUERY_INTERFACE1(nsRefreshDriver, nsITimerCallback)
+NS_IMPL_ISUPPORTS1(nsRefreshDriver, nsITimerCallback)
/*
* nsITimerCallback implementation
*/
NS_IMETHODIMP
nsRefreshDriver::Notify(nsITimer *aTimer)
{
UpdateMostRecentRefresh();
- nsPresContext *presContext = nsPresContext::FromRefreshDriver(this);
- nsCOMPtr<nsIPresShell> presShell = presContext->GetPresShell();
+ if (!mPresContext) {
+ // Things are being destroyed.
+ NS_ABORT_IF_FALSE(!mTimer, "timer should have been stopped");
+ return NS_OK;
+ }
+ nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
if (!presShell) {
// Things are being destroyed.
StopTimer();
return NS_OK;
}
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(mObservers); ++i) {
ObserverArray::EndLimitedIterator etor(mObservers[i]);
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -44,36 +44,39 @@
#define nsRefreshDriver_h_
#include "mozilla/TimeStamp.h"
#include "mozFlushType.h"
#include "nsITimer.h"
#include "nsCOMPtr.h"
#include "nsTObserverArray.h"
+class nsPresContext;
+
/**
* An abstract base class to be implemented by callers wanting to be
* notified at refresh times. When nothing needs to be painted, callers
* may not be notified.
*/
class nsARefreshObserver {
public:
virtual void WillRefresh(mozilla::TimeStamp aTime) = 0;
};
-/*
- * nsRefreshDriver MUST ONLY be constructed as a sub-object of
- * nsPresContext (since its reference counting methods forward to the
- * pres context of which it is an mRefreshDriver)
- */
-class nsRefreshDriver : private nsITimerCallback {
+class nsRefreshDriver : public nsITimerCallback {
public:
- nsRefreshDriver();
+ nsRefreshDriver(nsPresContext *aPresContext);
~nsRefreshDriver();
+ // nsISupports implementation
+ NS_DECL_ISUPPORTS
+
+ // nsITimerCallback implementation
+ NS_DECL_NSITIMERCALLBACK
+
/**
* Return the time of the most recent refresh. This is intended to be
* used by callers who want to start an animation now and want to know
* what time to consider the start of the animation. (This helps
* ensure that multiple animations started during the same event off
* the main event loop have the same start time.)
*/
mozilla::TimeStamp MostRecentRefresh() const;
@@ -90,31 +93,39 @@ public:
* painting, and, correspondingly, which get notified when there
* is a flush during such suppression
* and it must be either Flush_Style, Flush_Layout, or Flush_Display.
*/
PRBool AddRefreshObserver(nsARefreshObserver *aObserver,
mozFlushType aFlushType);
PRBool RemoveRefreshObserver(nsARefreshObserver *aObserver,
mozFlushType aFlushType);
-private:
- // nsISupports implementation
- NS_DECL_ISUPPORTS_INHERITED
- // nsITimerCallback implementation
- NS_IMETHOD Notify(nsITimer *aTimer);
+ /**
+ * Tell the refresh driver that it is done driving refreshes and
+ * should stop its timer and forget about its pres context. This may
+ * be called from within a refresh.
+ */
+ void Disconnect() {
+ StopTimer();
+ mPresContext = nsnull;
+ }
+private:
typedef nsTObserverArray<nsARefreshObserver*> ObserverArray;
void EnsureTimerStarted();
void StopTimer();
PRUint32 ObserverCount() const;
void UpdateMostRecentRefresh();
ObserverArray& ArrayFor(mozFlushType aFlushType);
nsCOMPtr<nsITimer> mTimer;
mozilla::TimeStamp mMostRecentRefresh; // only valid when mTimer non-null
+ nsPresContext *mPresContext; // weak; pres context passed in constructor
+ // and unset in Disconnect
+
// separate arrays for each flush type we support
ObserverArray mObservers[3];
};
#endif /* !defined(nsRefreshDriver_h_) */