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 84931 e251ac6325b49356548223f73f24624018d094d8
parent 84930 6ef4bf58a5c97559dcf4b24cca2f979d96a54ed2
child 84932 8fba04927c44b914d46ce8cb046a6b8dc5e43e36
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjoe
bugs712959
milestone12.0a1
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,