Bug 875609 - Refactor jump list code to decode images on the main thread. r=jimm
authorBrian R. Bondy <netzen@gmail.com>
Tue, 28 May 2013 14:08:48 -0400
changeset 133175 f6d827971b26cc62efe00c3a47322cb0cb1beb68
parent 133174 cd114424cc8645f0adc5ec7a752c67d1128aee77
child 133176 6d921704e199b9190f56be226c08742e429f4e1f
push id24744
push userryanvm@gmail.com
push dateWed, 29 May 2013 01:22:47 +0000
treeherdermozilla-central@495b385ae811 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs875609
milestone24.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 875609 - Refactor jump list code to decode images on the main thread. r=jimm
widget/windows/JumpListBuilder.cpp
widget/windows/WinUtils.cpp
widget/windows/WinUtils.h
--- a/widget/windows/JumpListBuilder.cpp
+++ b/widget/windows/JumpListBuilder.cpp
@@ -12,18 +12,16 @@
 #include "nsString.h"
 #include "nsArrayUtils.h"
 #include "nsIMutableArray.h"
 #include "nsWidgetsCID.h"
 #include "WinTaskbar.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsISimpleEnumerator.h"
 #include "mozilla/Preferences.h"
-#include "imgIContainer.h"
-#include "imgITools.h"
 #include "nsStringStream.h"
 #include "nsNetUtil.h"
 #include "nsThreadUtils.h"
 #include "mozilla/LazyIdleThread.h"
 
 #include "WinUtils.h"
 
 // The amount of time, in milliseconds, that our IO thread will stay alive after the last event it processes.
--- a/widget/windows/WinUtils.cpp
+++ b/widget/windows/WinUtils.cpp
@@ -34,17 +34,17 @@
 
 namespace mozilla {
 namespace widget {
 
   NS_IMPL_ISUPPORTS1(myDownloadObserver, nsIDownloadObserver)
 #ifdef MOZ_PLACES
   NS_IMPL_ISUPPORTS1(AsyncFaviconDataReady, nsIFaviconDataCallback)
 #endif
-  NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncWriteIconToDisk, nsIRunnable)
+  NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncEncodeAndWriteIcon, nsIRunnable)
   NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncDeleteIconFromDisk, nsIRunnable)
   NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncDeleteAllFaviconsFromDisk, nsIRunnable)
 
 
   const char FaviconHelper::kJumpListCacheDir[] = "jumpListCache";
   const char FaviconHelper::kShortcutCacheDir[] = "shortcutCache";
 
 // apis available on vista and up.
@@ -496,17 +496,16 @@ myDownloadObserver::OnDownloadComplete(n
                                      nsIRequest *request, 
                                      nsISupports *ctxt, 
                                      nsresult status, 
                                      nsIFile *result)
 {
   return NS_OK;
 }
 
-
 nsresult AsyncFaviconDataReady::OnFaviconDataNotAvailable(void)
 {
   if (!mURLShortcut) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIFile> icoFile;
   nsresult rv = FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut);
@@ -526,18 +525,16 @@ nsresult AsyncFaviconDataReady::OnFavico
   nsCOMPtr<nsIStreamListener> listener;
   rv = NS_NewDownloader(getter_AddRefs(listener), downloadObserver, icoFile);
   NS_ENSURE_SUCCESS(rv, rv);
 
   channel->AsyncOpen(listener, NULL);
   return NS_OK;
 }
 
-
-
 NS_IMETHODIMP
 AsyncFaviconDataReady::OnComplete(nsIURI *aFaviconURI,
                                   uint32_t aDataLen,
                                   const uint8_t *aData, 
                                   const nsACString &aMimeType)
 {
   if (!aDataLen || !aData) {
     if (mURLShortcut) {
@@ -550,122 +547,126 @@ AsyncFaviconDataReady::OnComplete(nsIURI
   nsCOMPtr<nsIFile> icoFile;
   nsresult rv = FaviconHelper::GetOutputIconPath(mNewURI, icoFile, mURLShortcut);
   NS_ENSURE_SUCCESS(rv, rv);
   
   nsAutoString path;
   rv = icoFile->GetPath(path);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  // Convert the obtained favicon data to an input stream
+  nsCOMPtr<nsIInputStream> stream;
+  rv = NS_NewByteInputStream(getter_AddRefs(stream),
+                             reinterpret_cast<const char*>(aData),
+                             aDataLen,
+                             NS_ASSIGNMENT_DEPEND);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Decode the image from the format it was returned to us in (probably PNG)
+  nsAutoCString mimeTypeOfInputData;
+  mimeTypeOfInputData.AssignLiteral("image/vnd.microsoft.icon");
+  nsCOMPtr<imgIContainer> container;
+  nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1");
+  rv = imgtool->DecodeImageData(stream, aMimeType,
+                                getter_AddRefs(container));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsRefPtr<gfxASurface> imgFrame;
+  rv = container->GetFrame(imgIContainer::FRAME_FIRST, 0, getter_AddRefs(imgFrame));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsRefPtr<gfxImageSurface> imageSurface;
+  gfxIntSize size;
+  if (mURLShortcut) {
+    imageSurface =
+      new gfxImageSurface(gfxIntSize(48, 48),
+                          gfxImageSurface::ImageFormatARGB32);
+    gfxContext context(imageSurface);
+    context.SetOperator(gfxContext::OPERATOR_SOURCE);
+    context.SetColor(gfxRGBA(1, 1, 1, 1));
+    context.Rectangle(gfxRect(0, 0, 48, 48));
+    context.Fill();
+
+    context.Translate(gfxPoint(16, 16));
+    context.SetOperator(gfxContext::OPERATOR_OVER);
+    context.DrawSurface(imgFrame,  gfxSize(16, 16));
+    size = imageSurface->GetSize();
+  } else {
+    imageSurface = imgFrame->GetAsReadableARGB32ImageSurface();
+    size.width = GetSystemMetrics(SM_CXSMICON);
+    size.height = GetSystemMetrics(SM_CYSMICON);
+    if (!size.width || !size.height) {
+      size.width = 16;
+      size.height = 16;
+    }
+  }
+
   // Allocate a new buffer that we own and can use out of line in 
   // another thread.  Copy the favicon raw data into it.
   const fallible_t fallible = fallible_t();
-  uint8_t *data = new (fallible) uint8_t[aDataLen];
+  uint8_t *data = new (fallible) uint8_t[imageSurface->GetDataSize()];
   if (!data) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
-  memcpy(data, aData, aDataLen);
+  memcpy(data, imageSurface->Data(), imageSurface->GetDataSize());
 
-  //AsyncWriteIconToDisk takes ownership of the heap allocated buffer.
-  nsCOMPtr<nsIRunnable> event = new AsyncWriteIconToDisk(path, aMimeType, 
-                                                         data, 
-                                                         aDataLen,
-                                                         mURLShortcut);
+  // AsyncEncodeAndWriteIcon takes ownership of the heap allocated buffer
+  nsCOMPtr<nsIRunnable> event = new AsyncEncodeAndWriteIcon(path, data,
+                                                            imageSurface->GetDataSize(),
+                                                            imageSurface->Stride(),
+                                                            size.width,
+                                                            size.height,
+                                                            mURLShortcut);
   mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
 
   return NS_OK;
 }
 #endif
 
-// Warning: AsyncWriteIconToDisk assumes ownership of the aData buffer passed in
-AsyncWriteIconToDisk::AsyncWriteIconToDisk(const nsAString &aIconPath,
-                                           const nsACString &aMimeTypeOfInputData,
-                                           uint8_t *aBuffer, 
-                                           uint32_t aBufferLength,
-                                           const bool aURLShortcut): 
+// Warning: AsyncEncodeAndWriteIcon assumes ownership of the aData buffer passed in
+AsyncEncodeAndWriteIcon::AsyncEncodeAndWriteIcon(const nsAString &aIconPath,
+                                                 uint8_t *aBuffer,
+                                                 uint32_t aBufferLength,
+                                                 uint32_t aStride,
+                                                 uint32_t aWidth,
+                                                 uint32_t aHeight,
+                                                 const bool aURLShortcut) :
   mURLShortcut(aURLShortcut),
   mIconPath(aIconPath),
-  mMimeTypeOfInputData(aMimeTypeOfInputData),
   mBuffer(aBuffer),
-  mBufferLength(aBufferLength)
-
+  mBufferLength(aBufferLength),
+  mStride(aStride),
+  mWidth(aWidth),
+  mHeight(aHeight)
 {
 }
 
-NS_IMETHODIMP AsyncWriteIconToDisk::Run()
+NS_IMETHODIMP AsyncEncodeAndWriteIcon::Run()
 {
   NS_PRECONDITION(!NS_IsMainThread(), "Should not be called on the main thread.");
 
-  // Convert the obtained favicon data to an input stream
-  nsCOMPtr<nsIInputStream> stream;
-  nsresult rv = 
-    NS_NewByteInputStream(getter_AddRefs(stream),
-                          reinterpret_cast<const char*>(mBuffer.get()),
-                          mBufferLength,
-                          NS_ASSIGNMENT_DEPEND);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Decode the image from the format it was returned to us in (probably PNG)
-  nsCOMPtr<imgIContainer> container;
-  nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1");
-  rv = imgtool->DecodeImageData(stream, mMimeTypeOfInputData, 
-                                getter_AddRefs(container));
-  NS_ENSURE_SUCCESS(rv, rv);
-
   // Get the recommended icon width and height, or if failure to obtain 
   // these settings, fall back to 16x16 ICOs.  These values can be different
   // if the user has a different DPI setting other than 100%.
   // Windows would scale the 16x16 icon themselves, but it's better
   // we let our ICO encoder do it.
   nsCOMPtr<nsIInputStream> iconStream;
-  if (!mURLShortcut) {
-    int32_t systemIconWidth = GetSystemMetrics(SM_CXSMICON);
-    int32_t systemIconHeight = GetSystemMetrics(SM_CYSMICON);
-    if ((systemIconWidth == 0 || systemIconHeight == 0)) {
-      systemIconWidth = 16;
-      systemIconHeight = 16;
-    }
-    // Scale the image to the needed size and in ICO format
-    mMimeTypeOfInputData.AssignLiteral("image/vnd.microsoft.icon");
-    rv = imgtool->EncodeScaledImage(container, mMimeTypeOfInputData,
-                                    systemIconWidth,
-                                    systemIconHeight,
-                                    EmptyString(),
-                                    getter_AddRefs(iconStream));
-    } else {
-      nsRefPtr<gfxASurface> s;
-      rv = container->GetFrame(imgIContainer::FRAME_FIRST, 0, getter_AddRefs(s));
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      gfxImageSurface* surface =
-        new gfxImageSurface(gfxIntSize(48, 48),
-                            gfxImageSurface::ImageFormatARGB32);
-      gfxContext context(surface);
-      context.SetOperator(gfxContext::OPERATOR_SOURCE);
-      context.SetColor(gfxRGBA(1, 1, 1, 1));
-      context.Rectangle(gfxRect(0, 0, 48, 48));
-      context.Fill();
-
-      context.Translate(gfxPoint(16, 16));
-      context.SetOperator(gfxContext::OPERATOR_OVER);
-      context.DrawSurface(s,  gfxSize(16, 16));
-      gfxIntSize size = surface->GetSize();
-
-      nsRefPtr<imgIEncoder> encoder = 
-        do_CreateInstance("@mozilla.org/image/encoder;2?"
-                          "type=image/vnd.microsoft.icon");
-      NS_ENSURE_TRUE(encoder, NS_ERROR_FAILURE);
-      rv = encoder->InitFromData(surface->Data(), surface->Stride() * size.height,
-                            size.width, size.height, surface->Stride(),
-                            imgIEncoder::INPUT_FORMAT_HOSTARGB, EmptyString());
-      NS_ENSURE_SUCCESS(rv, rv);
-      CallQueryInterface(encoder.get(), getter_AddRefs(iconStream));
-      if (!iconStream) {
-        return NS_ERROR_FAILURE;
-      }
+  nsRefPtr<imgIEncoder> encoder =
+    do_CreateInstance("@mozilla.org/image/encoder;2?"
+                      "type=image/vnd.microsoft.icon");
+  NS_ENSURE_TRUE(encoder, NS_ERROR_FAILURE);
+  nsresult rv = encoder->InitFromData(mBuffer, mBufferLength,
+                                      mWidth, mHeight,
+                                      mStride,
+                                      imgIEncoder::INPUT_FORMAT_HOSTARGB,
+                                      EmptyString());
+  NS_ENSURE_SUCCESS(rv, rv);
+  CallQueryInterface(encoder.get(), getter_AddRefs(iconStream));
+  if (!iconStream) {
+    return NS_ERROR_FAILURE;
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<nsIFile> icoFile
     = do_CreateInstance("@mozilla.org/file/local;1");
   NS_ENSURE_TRUE(icoFile, NS_ERROR_FAILURE);
   rv = icoFile->InitWithPath(mIconPath);
 
@@ -699,17 +700,17 @@ NS_IMETHODIMP AsyncWriteIconToDisk::Run(
   bufferedOutputStream->Close();
   outputStream->Close();
   if (mURLShortcut) {
     SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS, 0);
   }
   return rv;
 }
 
-AsyncWriteIconToDisk::~AsyncWriteIconToDisk()
+AsyncEncodeAndWriteIcon::~AsyncEncodeAndWriteIcon()
 {
 }
 
 AsyncDeleteIconFromDisk::AsyncDeleteIconFromDisk(const nsAString &aIconPath)
   : mIconPath(aIconPath)
 {
 }
 
--- a/widget/windows/WinUtils.h
+++ b/widget/windows/WinUtils.h
@@ -273,38 +273,41 @@ private:
   nsCOMPtr<nsIThread> mIOThread;
   const bool mURLShortcut;
 };
 #endif
 
 /**
   * Asynchronously tries add the list to the build
   */
-class AsyncWriteIconToDisk : public nsIRunnable
+class AsyncEncodeAndWriteIcon : public nsIRunnable
 {
 public:
   const bool mURLShortcut;
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
 
-  // Warning: AsyncWriteIconToDisk assumes ownership of the aData buffer passed in
-  AsyncWriteIconToDisk(const nsAString &aIconPath,
-                       const nsACString &aMimeTypeOfInputData,
-                       uint8_t *aData, 
-                       uint32_t aDataLen,
-                       const bool aURLShortcut);
-  virtual ~AsyncWriteIconToDisk();
+  // Warning: AsyncEncodeAndWriteIcon assumes ownership of the aData buffer passed in
+  AsyncEncodeAndWriteIcon(const nsAString &aIconPath,
+                          uint8_t *aData, uint32_t aDataLen, uint32_t aStride,
+                          uint32_t aWidth, uint32_t aHeight,
+                          const bool aURLShortcut);
+  virtual ~AsyncEncodeAndWriteIcon();
 
 private:
   nsAutoString mIconPath;
   nsAutoCString mMimeTypeOfInputData;
   nsAutoArrayPtr<uint8_t> mBuffer;
   uint32_t mBufferLength;
+  uint32_t mStride;
+  uint32_t mWidth;
+  uint32_t mHeight;
 };
 
+
 class AsyncDeleteIconFromDisk : public nsIRunnable
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
 
   AsyncDeleteIconFromDisk(const nsAString &aIconPath);
   virtual ~AsyncDeleteIconFromDisk();