Bug 712959 - Imagelib should notice when all image.mem.* prefs change. r=joe
authorJustin Lebar <justin.lebar@gmail.com>
Thu, 22 Dec 2011 09:21:00 -0500
changeset 86148 e251ac6325b49356548223f73f24624018d094d8
parent 86147 6ef4bf58a5c97559dcf4b24cca2f979d96a54ed2
child 86149 8fba04927c44b914d46ce8cb046a6b8dc5e43e36
push id674
push userffxbld
push dateTue, 13 Mar 2012 21:17:50 +0000
treeherdermozilla-beta@e3c4c92dec31 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjoe
bugs712959
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 712959 - Imagelib should notice when all image.mem.* prefs change. r=joe
image/src/DiscardTracker.cpp
image/src/RasterImage.cpp
image/src/RasterImage.h
image/src/imgRequest.cpp
--- a/image/src/DiscardTracker.cpp
+++ b/image/src/DiscardTracker.cpp
@@ -141,32 +141,42 @@ DiscardTracker::DiscardAll()
   // Add the sentinel back to the (now empty) list.
   Reset(&sSentinel);
 
   // Because the sentinel is the only element in the list, the next timer event
   // would be a no-op.  Disable the timer as an optimization.
   TimerOff();
 }
 
+static int
+DiscardTimeoutChangedCallback(const char* aPref, void *aClosure)
+{
+  DiscardTracker::ReloadTimeout();
+  return 0;
+}
+
 /**
  * Initialize the tracker.
  */
 nsresult
 DiscardTracker::Initialize()
 {
   nsresult rv;
 
   // Set up the list. Head<->Sentinel<->Tail
   sHead.curr = sTail.curr = sSentinel.curr = nsnull;
   sHead.prev = sTail.next = nsnull;
   sHead.next = sTail.prev = &sSentinel;
   sSentinel.prev = &sHead;
   sSentinel.next = &sTail;
 
-  // Load the timeout
+  // Watch the timeout pref for changes.
+  Preferences::RegisterCallback(DiscardTimeoutChangedCallback,
+                                DISCARD_TIMEOUT_PREF);
+
   ReloadTimeout();
 
   // Create and start the timer
   nsCOMPtr<nsITimer> t = do_CreateInstance("@mozilla.org/timer;1");
   NS_ENSURE_TRUE(t, NS_ERROR_OUT_OF_MEMORY);
   t.forget(&sTimer);
   rv = TimerOn();
   NS_ENSURE_SUCCESS(rv, rv);
@@ -186,17 +196,17 @@ DiscardTracker::Shutdown()
   if (sTimer) {
     sTimer->Cancel();
     NS_RELEASE(sTimer);
     sTimer = nsnull;
   }
 }
 
 /**
- * Sets the minimum timeout.
+ * Read the discard timeout from about:config.
  */
 void
 DiscardTracker::ReloadTimeout()
 {
   nsresult rv;
 
   // read the timeout pref
   PRInt32 discardTimeout;
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -53,16 +53,17 @@
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsAutoPtr.h"
 #include "nsStringStream.h"
 #include "prmem.h"
 #include "prenv.h"
 #include "ImageLogging.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/Preferences.h"
 #include "ImageLayers.h"
 
 #include "nsPNGDecoder.h"
 #include "nsGIFDecoder2.h"
 #include "nsJPEGDecoder.h"
 #include "nsBMPDecoder.h"
 #include "nsICODecoder.h"
 #include "nsIconDecoder.h"
@@ -79,35 +80,34 @@ using namespace mozilla::layers;
 
 /* Accounting for compressed data */
 #if defined(PR_LOGGING)
 static PRLogModuleInfo *gCompressedImageAccountingLog = PR_NewLogModule ("CompressedImageAccounting");
 #else
 #define gCompressedImageAccountingLog
 #endif
 
-// Tweakable progressive decoding parameters
-static PRUint32 gDecodeBytesAtATime = 200000;
-static PRUint32 gMaxMSBeforeYield = 400;
-static PRUint32 gMaxBytesForSyncDecode = 150000;
-
-void
-RasterImage::SetDecodeBytesAtATime(PRUint32 aBytesAtATime)
+// Tweakable progressive decoding parameters.  These are initialized to 0 here
+// because otherwise, we have to initialize them in a static initializer, which
+// makes us slower to start up.
+static bool gInitializedPrefCaches = false;
+static PRUint32 gDecodeBytesAtATime = 0;
+static PRUint32 gMaxMSBeforeYield = 0;
+static PRUint32 gMaxBytesForSyncDecode = 0;
+
+static void
+InitPrefCaches()
 {
-  gDecodeBytesAtATime = aBytesAtATime;
-}
-void
-RasterImage::SetMaxMSBeforeYield(PRUint32 aMaxMS)
-{
-  gMaxMSBeforeYield = aMaxMS;
-}
-void
-RasterImage::SetMaxBytesForSyncDecode(PRUint32 aMaxBytes)
-{
-  gMaxBytesForSyncDecode = aMaxBytes;
+  Preferences::AddUintVarCache(&gDecodeBytesAtATime,
+                               "image.mem.decode_bytes_at_a_time", 200000);
+  Preferences::AddUintVarCache(&gMaxMSBeforeYield,
+                               "image.mem.max_ms_before_yield", 400);
+  Preferences::AddUintVarCache(&gMaxBytesForSyncDecode,
+                               "image.mem.max_bytes_for_sync_decode", 150000);
+  gInitializedPrefCaches = true;
 }
 
 /* We define our own error checking macros here for 2 reasons:
  *
  * 1) Most of the failures we encounter here will (hopefully) be
  * the result of decoding failures (ie, bad data) and not code
  * failures. As such, we don't want to clutter up debug consoles
  * with spurious messages about NS_ENSURE_SUCCESS failures.
@@ -211,16 +211,21 @@ RasterImage::RasterImage(imgStatusTracke
 {
   // Set up the discard tracker node.
   mDiscardTrackerNode.curr = this;
   mDiscardTrackerNode.prev = mDiscardTrackerNode.next = nsnull;
   Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(0);
 
   // Statistics
   num_containers++;
+
+  // Register our pref observers if we haven't yet.
+  if (NS_UNLIKELY(!gInitializedPrefCaches)) {
+    InitPrefCaches();
+  }
 }
 
 //******************************************************************************
 RasterImage::~RasterImage()
 {
   delete mAnim;
 
   for (unsigned int i = 0; i < mFrames.Length(); ++i)
--- a/image/src/RasterImage.h
+++ b/image/src/RasterImage.h
@@ -339,21 +339,16 @@ public:
     kDisposeClearAll         = -1, // Clear the whole image, revealing
                                    // what was there before the gif displayed
     kDisposeNotSpecified,   // Leave frame, let new frame draw on top
     kDisposeKeep,           // Leave frame, let new frame draw on top
     kDisposeClear,          // Clear the frame's area, revealing bg
     kDisposeRestorePrevious // Restore the previous (composited) frame
   };
 
-  // Progressive decoding knobs
-  static void SetDecodeBytesAtATime(PRUint32 aBytesAtATime);
-  static void SetMaxMSBeforeYield(PRUint32 aMaxMS);
-  static void SetMaxBytesForSyncDecode(PRUint32 aMaxBytes);
-
   const char* GetURIString() { return mURIString.get();}
 
 private:
   struct Anim
   {
     //! Area of the first frame that needs to be redrawn on subsequent loops.
     nsIntRect                  firstFrameRefreshArea;
     PRUint32                   currentAnimationFrameIndex; // 0 to numFrames-1
--- a/image/src/imgRequest.cpp
+++ b/image/src/imgRequest.cpp
@@ -79,100 +79,31 @@
 #include "nsNetUtil.h"
 #include "nsIProtocolHandler.h"
 
 #include "mozilla/Preferences.h"
 
 #include "DiscardTracker.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 
-#define DISCARD_PREF "image.mem.discardable"
-#define DECODEONDRAW_PREF "image.mem.decodeondraw"
-#define BYTESATATIME_PREF "image.mem.decode_bytes_at_a_time"
-#define MAXMS_PREF "image.mem.max_ms_before_yield"
-#define MAXBYTESFORSYNC_PREF "image.mem.max_bytes_for_sync_decode"
 #define SVG_MIMETYPE "image/svg+xml"
 
 using namespace mozilla;
 using namespace mozilla::imagelib;
 
-/* Kept up to date by a pref observer. */
+static bool gInitializedPrefCaches = false;
 static bool gDecodeOnDraw = false;
 static bool gDiscardable = false;
 
-static const char* kObservedPrefs[] = {
-  DISCARD_PREF,
-  DECODEONDRAW_PREF,
-  DISCARD_TIMEOUT_PREF,
-  nsnull
-};
-
-/*
- * Pref observer goop. Yuck.
- */
-
-// Flag
-static bool gRegisteredPrefObserver = false;
-
-// Reloader
 static void
-ReloadPrefs()
+InitPrefCaches()
 {
-  // Discardable
-  gDiscardable = Preferences::GetBool(DISCARD_PREF, gDiscardable);
-
-  // Decode-on-draw
-  gDecodeOnDraw = Preferences::GetBool(DECODEONDRAW_PREF, gDecodeOnDraw);
-
-  // Progressive decoding knobs
-  PRInt32 bytesAtATime, maxMS, maxBytesForSync;
-  if (NS_SUCCEEDED(Preferences::GetInt(BYTESATATIME_PREF, &bytesAtATime))) {
-    RasterImage::SetDecodeBytesAtATime(bytesAtATime);
-  }
-
-  if (NS_SUCCEEDED(Preferences::GetInt(MAXMS_PREF, &maxMS))) {
-    RasterImage::SetMaxMSBeforeYield(maxMS);
-  }
-
-  if (NS_SUCCEEDED(Preferences::GetInt(MAXBYTESFORSYNC_PREF,
-                                       &maxBytesForSync))) {
-    RasterImage::SetMaxBytesForSyncDecode(maxBytesForSync);
-  }
-
-  // Discard timeout
-  mozilla::imagelib::DiscardTracker::ReloadTimeout();
-}
-
-// Observer
-class imgRequestPrefObserver : public nsIObserver {
-public:
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSIOBSERVER
-};
-NS_IMPL_ISUPPORTS1(imgRequestPrefObserver, nsIObserver)
-
-// Callback
-NS_IMETHODIMP
-imgRequestPrefObserver::Observe(nsISupports     *aSubject,
-                                const char      *aTopic,
-                                const PRUnichar *aData)
-{
-  // Right topic
-  NS_ABORT_IF_FALSE(!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID), "invalid topic");
-
-  // Right pref
-  if (strcmp(NS_LossyConvertUTF16toASCII(aData).get(), DISCARD_PREF) &&
-      strcmp(NS_LossyConvertUTF16toASCII(aData).get(), DECODEONDRAW_PREF) &&
-      strcmp(NS_LossyConvertUTF16toASCII(aData).get(), DISCARD_TIMEOUT_PREF))
-    return NS_OK;
-
-  // Process the change
-  ReloadPrefs();
-
-  return NS_OK;
+  Preferences::AddBoolVarCache(&gDiscardable, "image.mem.discardable");
+  Preferences::AddBoolVarCache(&gDecodeOnDraw, "image.mem.decodeondraw");
+  gInitializedPrefCaches = true;
 }
 
 #if defined(PR_LOGGING)
 PRLogModuleInfo *gImgLog = PR_NewLogModule("imgRequest");
 #endif
 
 NS_IMPL_ISUPPORTS8(imgRequest,
                    imgIDecoderObserver, imgIContainerObserver,
@@ -182,17 +113,22 @@ NS_IMPL_ISUPPORTS8(imgRequest,
                    nsIInterfaceRequestor,
                    nsIAsyncVerifyRedirectCallback)
 
 imgRequest::imgRequest() : 
   mValidator(nsnull), mImageSniffers("image-sniffing-services"),
   mInnerWindowId(0), mCORSMode(imgIRequest::CORS_NONE),
   mDecodeRequested(false), mIsMultiPartChannel(false), mGotData(false),
   mIsInCache(false)
-{}
+{
+  // Register our pref observers if we haven't yet.
+  if (NS_UNLIKELY(!gInitializedPrefCaches)) {
+    InitPrefCaches();
+  }
+}
 
 imgRequest::~imgRequest()
 {
   if (mURI) {
     nsCAutoString spec;
     mURI->GetSpec(spec);
     LOG_FUNC_WITH_PARAM(gImgLog, "imgRequest::~imgRequest()", "keyuri", spec.get());
   } else
@@ -235,24 +171,16 @@ nsresult imgRequest::Init(nsIURI *aURI,
                "Initializing with a channel that already calls back to us!");
 
   mChannel->SetNotificationCallbacks(this);
 
   mCacheEntry = aCacheEntry;
 
   SetLoadId(aLoadId);
 
-  // Register our pref observer if it hasn't been done yet.
-  if (NS_UNLIKELY(!gRegisteredPrefObserver)) {
-    nsCOMPtr<nsIObserver> observer(new imgRequestPrefObserver());
-    Preferences::AddStrongObservers(observer, kObservedPrefs);
-    ReloadPrefs();
-    gRegisteredPrefObserver = true;
-  }
-
   return NS_OK;
 }
 
 imgStatusTracker&
 imgRequest::GetStatusTracker()
 {
   if (mImage) {
     NS_ABORT_IF_FALSE(!mStatusTracker,