Bug 875609 - Refactor jump list code to decode images on the main thread. r=jimm. a=akeybl
authorBrian R. Bondy <netzen@gmail.com>
Tue, 28 May 2013 14:08:48 -0400
changeset 137748 86f7fda1f568131420616ecc3199bce4081ef0de
parent 137747 7a0168d559d8e641de1b010b5f700e4922ca7b81
child 137749 da2591d85389f5933c6714e75aa1523827188277
push id2542
push userryanvm@gmail.com
push dateTue, 04 Jun 2013 20:00:52 +0000
treeherdermozilla-beta@da2591d85389 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm, akeybl
bugs875609
milestone22.0
Bug 875609 - Refactor jump list code to decode images on the main thread. r=jimm. a=akeybl
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();