Bug 110894 - Use favicons on webpage shortcuts in Windows. r=bbondy
authorParth Mudgal <artpar@gmail.com>
Sat, 21 Jul 2012 16:07:26 -0400
changeset 100308 aa003aa3a18f365fd805dca30f5aef3ebc584344
parent 100307 03fae2283d808405bee71d2d97a5e4f93b19d6ef
child 100309 37c915daed4a175daa70ec0afdcd7b1937296d34
push id23175
push useremorley@mozilla.com
push dateWed, 25 Jul 2012 15:03:49 +0000
treeherdermozilla-central@75d16b99e8ab [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbondy
bugs110894
milestone17.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 110894 - Use favicons on webpage shortcuts in Windows. r=bbondy
widget/windows/JumpListBuilder.cpp
widget/windows/JumpListBuilder.h
widget/windows/JumpListItem.cpp
widget/windows/JumpListItem.h
widget/windows/WinUtils.cpp
widget/windows/WinUtils.h
widget/windows/nsDataObj.cpp
widget/windows/nsDataObj.h
--- a/widget/windows/JumpListBuilder.cpp
+++ b/widget/windows/JumpListBuilder.cpp
@@ -19,16 +19,18 @@
 #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.
 #define DEFAULT_THREAD_TIMEOUT_MS 30000
 
 namespace mozilla {
 namespace widget {
 
 static NS_DEFINE_CID(kJumpListItemCID,     NS_WIN_JUMPLISTITEM_CID);
 static NS_DEFINE_CID(kJumpListLinkCID,     NS_WIN_JUMPLISTLINK_CID);
@@ -36,20 +38,16 @@ static NS_DEFINE_CID(kJumpListShortcutCI
 
 // defined in WinTaskbar.cpp
 extern const wchar_t *gMozillaJumpListIDGeneric;
 
 bool JumpListBuilder::sBuildingList = false;
 const char kPrefTaskbarEnabled[] = "browser.taskbar.lists.enabled";
 
 NS_IMPL_ISUPPORTS2(JumpListBuilder, nsIJumpListBuilder, nsIObserver)
-NS_IMPL_ISUPPORTS1(AsyncFaviconDataReady, nsIFaviconDataCallback)
-NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncWriteIconToDisk, nsIRunnable)
-NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncDeleteIconFromDisk, nsIRunnable)
-NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncDeleteAllFaviconsFromDisk, nsIRunnable)
 
 JumpListBuilder::JumpListBuilder() :
   mMaxItems(0),
   mHasCommit(false)
 {
   ::CoInitialize(NULL);
   
   CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER,
@@ -177,17 +175,17 @@ nsresult JumpListBuilder::RemoveIconCach
           
           // The local file path is stored inside the nsIURI
           // Get the nsIURI spec which stores the local path for the icon to remove
           nsCAutoString spec;
           nsresult rv = uri->GetSpec(spec);
           NS_ENSURE_SUCCESS(rv, rv);
 
           nsCOMPtr<nsIRunnable> event 
-            = new AsyncDeleteIconFromDisk(NS_ConvertUTF8toUTF16(spec));
+            = new mozilla::widget::AsyncDeleteIconFromDisk(NS_ConvertUTF8toUTF16(spec));
           mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
 
           // The shortcut was generated from an IShellLinkW so IShellLinkW can
           // only tell us what the original icon is and not the URI.
           // So this field was used only temporarily as the actual icon file
           // path.  It should be cleared.
           shortcut->SetFaviconPageUri(nsnull);
         }
@@ -202,17 +200,18 @@ nsresult JumpListBuilder::RemoveIconCach
 // Ensures that we have no old ICO files left in the jump list cache
 nsresult JumpListBuilder::RemoveIconCacheForAllItems() 
 {
   // Construct the path of our jump list cache
   nsCOMPtr<nsIFile> jumpListCacheDir;
   nsresult rv = NS_GetSpecialDirectory("ProfLDS", 
                                        getter_AddRefs(jumpListCacheDir));
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = jumpListCacheDir->AppendNative(nsDependentCString(JumpListItem::kJumpListCacheDir));
+  rv = jumpListCacheDir->AppendNative(nsDependentCString(
+                         mozilla::widget::FaviconHelper::kJumpListCacheDir));
   NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<nsISimpleEnumerator> entries;
   rv = jumpListCacheDir->GetDirectoryEntries(getter_AddRefs(entries));
   NS_ENSURE_SUCCESS(rv, rv);
   
   // Loop through each directory entry and remove all ICO files found
   do {
     bool hasMore = false;
@@ -504,239 +503,19 @@ nsresult JumpListBuilder::TransferIObjec
 NS_IMETHODIMP JumpListBuilder::Observe(nsISupports* aSubject,
                                         const char* aTopic,
                                         const PRUnichar* aData)
 {
   if (nsDependentString(aData).EqualsASCII(kPrefTaskbarEnabled)) {
     bool enabled = Preferences::GetBool(kPrefTaskbarEnabled, true);
     if (!enabled) {
       
-      nsCOMPtr<nsIRunnable> event = new AsyncDeleteAllFaviconsFromDisk();
+      nsCOMPtr<nsIRunnable> event = 
+        new mozilla::widget::AsyncDeleteAllFaviconsFromDisk();
       mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
     }
   }
   return NS_OK;
 }
 
-
-AsyncFaviconDataReady::AsyncFaviconDataReady(nsIURI *aNewURI, 
-                                             nsCOMPtr<nsIThread> &aIOThread) 
-                      : mNewURI(aNewURI), 
-                        mIOThread(aIOThread)
-{
-}
-
-NS_IMETHODIMP
-AsyncFaviconDataReady::OnComplete(nsIURI *aFaviconURI,
-                                  PRUint32 aDataLen,
-                                  const PRUint8 *aData, 
-                                  const nsACString &aMimeType)
-{
-  if (!aDataLen || !aData) {
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsIFile> icoFile;
-  nsresult rv = JumpListShortcut::GetOutputIconPath(mNewURI, icoFile);
-  NS_ENSURE_SUCCESS(rv, rv);
-  nsAutoString path;
-  rv = icoFile->GetPath(path);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // 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();
-  PRUint8 *data = new (fallible) PRUint8[aDataLen];
-  if (!data) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-  memcpy(data, aData, aDataLen);
-
-  //AsyncWriteIconToDisk takes ownership of the heap allocated buffer.
-  nsCOMPtr<nsIRunnable> event = new AsyncWriteIconToDisk(path, aMimeType, 
-                                                         data, 
-                                                         aDataLen);
-  mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
-
-  return NS_OK;
-}
-
-// Warning: AsyncWriteIconToDisk assumes ownership of the aData buffer passed in
-AsyncWriteIconToDisk::AsyncWriteIconToDisk(const nsAString &aIconPath,
-                                           const nsACString &aMimeTypeOfInputData,
-                                           PRUint8 *aBuffer, 
-                                           PRUint32 aBufferLength)
-                     : mIconPath(aIconPath),
-                       mMimeTypeOfInputData(aMimeTypeOfInputData),
-                       mBuffer(aBuffer),
-                       mBufferLength(aBufferLength)
-
-{
-}
-
-NS_IMETHODIMP AsyncWriteIconToDisk::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.
-  PRInt32 systemIconWidth = GetSystemMetrics(SM_CXSMICON);
-  PRInt32 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");
-  nsCOMPtr<nsIInputStream> iconStream;
-  rv = imgtool->EncodeScaledImage(container, mMimeTypeOfInputData,
-                                  systemIconWidth,
-                                  systemIconHeight,
-                                  EmptyString(),
-                                  getter_AddRefs(iconStream));
-  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);
-
-  // Setup the output stream for the ICO file on disk
-  nsCOMPtr<nsIOutputStream> outputStream;
-  rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), icoFile);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Obtain the ICO buffer size from the re-encoded ICO stream
-  PRUint32 bufSize;
-  rv = iconStream->Available(&bufSize);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Setup a buffered output stream from the stream object
-  // so that we can simply use WriteFrom with the stream object
-  nsCOMPtr<nsIOutputStream> bufferedOutputStream;
-  rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
-                                  outputStream, bufSize);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Write out the icon stream to disk and make sure we wrote everything
-  PRUint32 wrote;
-  rv = bufferedOutputStream->WriteFrom(iconStream, bufSize, &wrote);
-  NS_ASSERTION(bufSize == wrote, "Icon wrote size should be equal to requested write size");
-
-  // Cleanup
-  bufferedOutputStream->Close();
-  outputStream->Close();
-  return rv;
-}
-
-AsyncWriteIconToDisk::~AsyncWriteIconToDisk()
-{
-}
-
-AsyncDeleteIconFromDisk::AsyncDeleteIconFromDisk(const nsAString &aIconPath)
-                        : mIconPath(aIconPath)
-{
-}
-
-NS_IMETHODIMP AsyncDeleteIconFromDisk::Run()
-{
-  // Construct the parent path of the passed in path
-  nsCOMPtr<nsIFile> icoFile = do_CreateInstance("@mozilla.org/file/local;1");
-  NS_ENSURE_TRUE(icoFile, NS_ERROR_FAILURE);
-  nsresult rv = icoFile->InitWithPath(mIconPath);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Check if the cached ICO file exists
-  bool exists;
-  rv = icoFile->Exists(&exists);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Check that we aren't deleting some arbitrary file that is not an icon
-  if (StringTail(mIconPath, 4).LowerCaseEqualsASCII(".ico")) {
-    // Check if the cached ICO file exists
-    bool exists;
-    if (NS_FAILED(icoFile->Exists(&exists)) || !exists)
-      return NS_ERROR_FAILURE;
-
-    // We found an ICO file that exists, so we should remove it
-    icoFile->Remove(false);
-  }
-
-  return NS_OK;
-}
-
-AsyncDeleteIconFromDisk::~AsyncDeleteIconFromDisk()
-{
-}
-
-AsyncDeleteAllFaviconsFromDisk::AsyncDeleteAllFaviconsFromDisk()
-{
-}
-
-NS_IMETHODIMP AsyncDeleteAllFaviconsFromDisk::Run()
-{
-  // Construct the path of our jump list cache
-  nsCOMPtr<nsIFile> jumpListCacheDir;
-  nsresult rv = NS_GetSpecialDirectory("ProfLDS", 
-    getter_AddRefs(jumpListCacheDir));
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = jumpListCacheDir->AppendNative(nsDependentCString(JumpListItem::kJumpListCacheDir));
-  NS_ENSURE_SUCCESS(rv, rv);
-  nsCOMPtr<nsISimpleEnumerator> entries;
-  rv = jumpListCacheDir->GetDirectoryEntries(getter_AddRefs(entries));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Loop through each directory entry and remove all ICO files found
-  do {
-    bool hasMore = false;
-    if (NS_FAILED(entries->HasMoreElements(&hasMore)) || !hasMore)
-      break;
-
-    nsCOMPtr<nsISupports> supp;
-    if (NS_FAILED(entries->GetNext(getter_AddRefs(supp))))
-      break;
-
-    nsCOMPtr<nsIFile> currFile(do_QueryInterface(supp));
-    nsAutoString path;
-    if (NS_FAILED(currFile->GetPath(path)))
-      continue;
-
-    PRInt32 len = path.Length();
-    if (StringTail(path, 4).LowerCaseEqualsASCII(".ico")) {
-      // Check if the cached ICO file exists
-      bool exists;
-      if (NS_FAILED(currFile->Exists(&exists)) || !exists)
-        continue;
-
-      // We found an ICO file that exists, so we should remove it
-      currFile->Remove(false);
-    }
-  } while(true);
-
-  return NS_OK;
-}
-
-AsyncDeleteAllFaviconsFromDisk::~AsyncDeleteAllFaviconsFromDisk()
-{
-}
-
-
 } // namespace widget
 } // namespace mozilla
 
--- a/widget/windows/JumpListBuilder.h
+++ b/widget/windows/JumpListBuilder.h
@@ -50,72 +50,13 @@ private:
   bool IsSeparator(nsCOMPtr<nsIJumpListItem>& item);
   nsresult TransferIObjectArrayToIMutableArray(IObjectArray *objArray, nsIMutableArray *removedItems);
   nsresult RemoveIconCacheForItems(nsIMutableArray *removedItems);
   nsresult RemoveIconCacheForAllItems();
 
   friend class WinTaskbar;
 };
 
-
-class AsyncFaviconDataReady MOZ_FINAL : public nsIFaviconDataCallback
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIFAVICONDATACALLBACK
-
-  AsyncFaviconDataReady(nsIURI *aNewURI, nsCOMPtr<nsIThread> &aIOThread);
-private:
-  nsCOMPtr<nsIURI> mNewURI;
-  nsCOMPtr<nsIThread> mIOThread;
-};
-
-/**
-  * Asynchronously tries add the list to the build
-  */
-class AsyncWriteIconToDisk : public nsIRunnable
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIRUNNABLE
-
-  // Warning: AsyncWriteIconToDisk assumes ownership of the aData buffer passed in
-  AsyncWriteIconToDisk(const nsAString &aIconPath,
-                       const nsACString &aMimeTypeOfInputData,
-                       PRUint8 *aData, 
-                       PRUint32 aDataLen);
-  virtual ~AsyncWriteIconToDisk();
-
-private:
-  nsAutoString mIconPath;
-  nsCAutoString mMimeTypeOfInputData;
-  nsAutoArrayPtr<PRUint8> mBuffer;
-  PRUint32 mBufferLength;
-};
-
-class AsyncDeleteIconFromDisk : public nsIRunnable
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIRUNNABLE
-
-  AsyncDeleteIconFromDisk(const nsAString &aIconPath);
-  virtual ~AsyncDeleteIconFromDisk();
-
-private:
-  nsAutoString mIconPath;
-};
-
-class AsyncDeleteAllFaviconsFromDisk : public nsIRunnable
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIRUNNABLE
-
-  AsyncDeleteAllFaviconsFromDisk();
-  virtual ~AsyncDeleteAllFaviconsFromDisk();
-};
-
 } // namespace widget
 } // namespace mozilla
 
 #endif /* __JumpListBuilder_h__ */
 
--- a/widget/windows/JumpListItem.cpp
+++ b/widget/windows/JumpListItem.cpp
@@ -18,18 +18,16 @@
 #include "mozIAsyncFavicons.h"
 #include "mozilla/Preferences.h"
 #include "JumpListBuilder.h"
 #include "WinUtils.h"
 
 namespace mozilla {
 namespace widget {
 
-const char JumpListItem::kJumpListCacheDir[] = "jumpListCache";
-
 // ISUPPORTS Impl's
 NS_IMPL_ISUPPORTS1(JumpListItem,
                    nsIJumpListItem)
 
 NS_IMPL_ISUPPORTS_INHERITED1(JumpListSeparator,
                              JumpListItem,
                              nsIJumpListSeparator)
 
@@ -117,36 +115,36 @@ NS_IMETHODIMP JumpListLink::GetUriTitle(
 }
 
 /* readonly attribute long uriHash; */
 NS_IMETHODIMP JumpListLink::GetUriHash(nsACString& aUriHash)
 {
   if (!mURI)
     return NS_ERROR_NOT_AVAILABLE;
 
-  return JumpListItem::HashURI(mCryptoHash, mURI, aUriHash);
+  return mozilla::widget::FaviconHelper::HashURI(mCryptoHash, mURI, aUriHash);
 }
 
 /* boolean compareHash(in nsIURI uri); */
 NS_IMETHODIMP JumpListLink::CompareHash(nsIURI *aUri, bool *aResult)
 {
   nsresult rv;
 
   if (!mURI) {
     *aResult = !aUri;
     return NS_OK;
   }
 
   NS_ENSURE_ARG_POINTER(aUri);
 
   nsCAutoString hash1, hash2;
 
-  rv = JumpListItem::HashURI(mCryptoHash, mURI, hash1);
+  rv = mozilla::widget::FaviconHelper::HashURI(mCryptoHash, mURI, hash1);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = JumpListItem::HashURI(mCryptoHash, aUri, hash2);
+  rv = mozilla::widget::FaviconHelper::HashURI(mCryptoHash, aUri, hash2);
   NS_ENSURE_SUCCESS(rv, rv);
 
   *aResult = hash1.Equals(hash2);
 
   return NS_OK;
 }
 
 /* boolean equals(nsIJumpListItem item); */
@@ -316,145 +314,16 @@ nsresult JumpListSeparator::GetSeparator
 
   PropVariantClear(&pv);
 
   aShellLink = dont_AddRef(psl);
 
   return NS_OK;
 }
 
-// Obtains the jump list 'ICO cache timeout in seconds' pref
-static PRInt32 GetICOCacheSecondsTimeout() {
-
-  // Only obtain the setting at most once from the pref service.
-  // In the rare case that 2 threads call this at the same
-  // time it is no harm and we will simply obtain the pref twice.
-  // None of the taskbar list prefs are currently updated via a
-  // pref observer so I think this should suffice.
-  const PRInt32 kSecondsPerDay = 86400;
-  static bool alreadyObtained = false;
-  static PRInt32 icoReCacheSecondsTimeout = kSecondsPerDay;
-  if (alreadyObtained) {
-    return icoReCacheSecondsTimeout;
-  }
-
-  // Obtain the pref
-  const char PREF_ICOTIMEOUT[]  = "browser.taskbar.lists.icoTimeoutInSeconds";
-  icoReCacheSecondsTimeout = Preferences::GetInt(PREF_ICOTIMEOUT, 
-                                                 kSecondsPerDay);
-  alreadyObtained = true;
-  return icoReCacheSecondsTimeout;
-}
-
-// (static) If the data is available, will return the path on disk where 
-// the favicon for page aFaviconPageURI is stored.  If the favicon does not
-// exist, or its cache is expired, this method will kick off an async request
-// for the icon so that next time the method is called it will be available. 
-nsresult JumpListShortcut::ObtainCachedIconFile(nsCOMPtr<nsIURI> aFaviconPageURI,
-                                                nsString &aICOFilePath,
-                                                nsCOMPtr<nsIThread> &aIOThread)
-{
-  // Obtain the ICO file path
-  nsCOMPtr<nsIFile> icoFile;
-  nsresult rv = GetOutputIconPath(aFaviconPageURI, icoFile);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Check if the cached ICO file already exists
-  bool exists;
-  rv = icoFile->Exists(&exists);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (exists) {
-
-    // Obtain the file's last modification date in seconds
-    PRInt64 fileModTime = LL_ZERO;
-    rv = icoFile->GetLastModifiedTime(&fileModTime);
-    fileModTime /= PR_MSEC_PER_SEC;
-    PRInt32 icoReCacheSecondsTimeout = GetICOCacheSecondsTimeout();
-    PRInt64 nowTime = PR_Now() / PRInt64(PR_USEC_PER_SEC);
-
-    // If the last mod call failed or the icon is old then re-cache it
-    // This check is in case the favicon of a page changes
-    // the next time we try to build the jump list, the data will be available.
-    if (NS_FAILED(rv) ||
-        (nowTime - fileModTime) > icoReCacheSecondsTimeout) {
-      CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread);
-      return NS_ERROR_NOT_AVAILABLE;
-    }
-  } else {
-
-    // The file does not exist yet, obtain it async from the favicon service so that
-    // the next time we try to build the jump list it'll be available.
-    CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread);
-    return NS_ERROR_NOT_AVAILABLE;
-  }
-
-  // The icoFile is filled with a path that exists, get its path
-  rv = icoFile->GetPath(aICOFilePath);
-  return rv;
-}
-
-// (static) Obtains the ICO file for the favicon at page aFaviconPageURI
-// If successful, the file path on disk is in the format:
-// <ProfLDS>\jumpListCache\<hash(aFaviconPageURI)>.ico
-nsresult JumpListShortcut::GetOutputIconPath(nsCOMPtr<nsIURI> aFaviconPageURI,
-                                             nsCOMPtr<nsIFile> &aICOFile) 
-{
-  // Hash the input URI and replace any / with _
-  nsCAutoString inputURIHash;
-  nsCOMPtr<nsICryptoHash> cryptoHash;
-  nsresult rv = JumpListItem::HashURI(cryptoHash, aFaviconPageURI,
-                                      inputURIHash);
-  NS_ENSURE_SUCCESS(rv, rv);
-  char* cur = inputURIHash.BeginWriting();
-  char* end = inputURIHash.EndWriting();
-  for (; cur < end; ++cur) {
-    if ('/' == *cur) {
-      *cur = '_';
-    }
-  }
-
-  // Obtain the local profile directory and construct the output icon file path
-  rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(aICOFile));
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = aICOFile->AppendNative(nsDependentCString(JumpListItem::kJumpListCacheDir));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Try to create the directory if it's not there yet
-  rv = aICOFile->Create(nsIFile::DIRECTORY_TYPE, 0777);
-  if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) {
-    return rv;
-  }
-  
-  // Append the icon extension
-  inputURIHash.Append(".ico");
-  rv = aICOFile->AppendNative(inputURIHash);
-
-  return rv;
-}
-
-// (static) Asynchronously creates a cached ICO file on disk for the favicon of
-// page aFaviconPageURI and stores it to disk at the path of aICOFile.
-nsresult 
-JumpListShortcut::CacheIconFileFromFaviconURIAsync(nsCOMPtr<nsIURI> aFaviconPageURI,
-                                                   nsCOMPtr<nsIFile> aICOFile,
-                                                   nsCOMPtr<nsIThread> &aIOThread)
-{
-  // Obtain the favicon service and get the favicon for the specified page
-  nsCOMPtr<mozIAsyncFavicons> favIconSvc(
-                      do_GetService("@mozilla.org/browser/favicon-service;1"));
-  NS_ENSURE_TRUE(favIconSvc, NS_ERROR_FAILURE);
-
-  nsCOMPtr<nsIFaviconDataCallback> callback = 
-    new AsyncFaviconDataReady(aFaviconPageURI, aIOThread);
-
-  favIconSvc->GetFaviconDataForPage(aFaviconPageURI, callback);
-  return NS_OK;
-}
-
 // (static) Creates a ShellLink that encapsulate a shortcut to local apps.
 nsresult JumpListShortcut::GetShellLink(nsCOMPtr<nsIJumpListItem>& item, 
                                         nsRefPtr<IShellLinkW>& aShellLink,
                                         nsCOMPtr<nsIThread> &aIOThread)
 {
   HRESULT hr;
   IShellLinkW* psl;
   nsresult rv;
@@ -539,17 +408,20 @@ nsresult JumpListShortcut::GetShellLink(
 
   // Store the rest of the params
   psl->SetPath(appPath.get());
   psl->SetDescription(appDescription.get());
   psl->SetArguments(appArgs.get());
 
   if (useUriIcon) {
     nsString icoFilePath;
-    rv = ObtainCachedIconFile(iconUri, icoFilePath, aIOThread);
+    rv = mozilla::widget::FaviconHelper::ObtainCachedIconFile(iconUri, 
+                                                              icoFilePath, 
+                                                              aIOThread,
+                                                              false);
     if (NS_SUCCEEDED(rv)) {
       // Always use the first icon in the ICO file
       // our encoded icon only has 1 resource
       psl->SetIconLocation(icoFilePath.get(), 0);
       usedUriIcon = true;
     }
   }
 
@@ -572,17 +444,17 @@ static nsresult IsPathInOurIconCache(nsC
   NS_ENSURE_ARG_POINTER(aSame);
  
   *aSame = false;
 
   // Construct the path of our jump list cache
   nsCOMPtr<nsIFile> jumpListCache;
   nsresult rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(jumpListCache));
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = jumpListCache->AppendNative(nsDependentCString(JumpListItem::kJumpListCacheDir));
+  rv = jumpListCache->AppendNative(nsDependentCString(FaviconHelper::kJumpListCacheDir));
   NS_ENSURE_SUCCESS(rv, rv);
   nsAutoString jumpListCachePath;
   rv = jumpListCache->GetPath(jumpListCachePath);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Construct the parent path of the passed in path
   nsCOMPtr<nsIFile> passedInFile = do_CreateInstance("@mozilla.org/file/local;1");
   NS_ENSURE_TRUE(passedInFile, NS_ERROR_FAILURE);
@@ -767,38 +639,11 @@ bool JumpListShortcut::ExecutableExists(
   if (NS_SUCCEEDED(rv) && executable) {
     bool exists;
     executable->Exists(&exists);
     return exists;
   }
   return false;
 }
 
-// (static) Helper method which will hash a URI
-nsresult JumpListItem::HashURI(nsCOMPtr<nsICryptoHash> &aCryptoHash, 
-                               nsIURI *aUri, nsACString& aUriHash)
-{
-  if (!aUri)
-    return NS_ERROR_INVALID_ARG;
-
-  nsCAutoString spec;
-  nsresult rv = aUri->GetSpec(spec);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!aCryptoHash) {
-    aCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  rv = aCryptoHash->Init(nsICryptoHash::MD5);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = aCryptoHash->Update(reinterpret_cast<const PRUint8*>(spec.BeginReading()), 
-                                                            spec.Length());
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = aCryptoHash->Finish(true, aUriHash);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
 } // namespace widget
 } // namespace mozilla
 
--- a/widget/windows/JumpListItem.h
+++ b/widget/windows/JumpListItem.h
@@ -43,18 +43,16 @@ public:
   NS_DECL_NSIJUMPLISTITEM
 
   static const char kJumpListCacheDir[];
 
 protected:
   short Type() { return mItemType; }
   short mItemType;
 
-  static nsresult HashURI(nsCOMPtr<nsICryptoHash> &aCryptoHash,
-                          nsIURI *aUri, nsACString& aUriHash);
 };
 
 class JumpListSeparator : public JumpListItem, public nsIJumpListSeparator
 {
 public:
   JumpListSeparator() :
    JumpListItem(nsIJumpListItem::JUMPLIST_ITEM_SEPARATOR)
   {}
--- a/widget/windows/WinUtils.cpp
+++ b/widget/windows/WinUtils.cpp
@@ -6,19 +6,43 @@
 
 #include "WinUtils.h"
 #include "nsWindow.h"
 #include "nsWindowDefs.h"
 #include "nsGUIEvent.h"
 #include "nsIDOMMouseEvent.h"
 #include "mozilla/Preferences.h"
 
+#include "nsString.h"
+#include "nsDirectoryServiceUtils.h"
+#include "imgIContainer.h"
+#include "imgITools.h"
+#include "nsStringStream.h"
+#include "nsNetUtil.h"
+#include "mozIAsyncFavicons.h"
+ 
+#include "nsIIconURI.h"
+#include "nsIDownloader.h"
+#include "nsINetUtil.h"
+#include "nsIChannel.h"
+#include "nsIObserver.h"
+
 namespace mozilla {
 namespace widget {
 
+  NS_IMPL_ISUPPORTS1(myDownloadObserver, nsIDownloadObserver)
+  NS_IMPL_ISUPPORTS1(AsyncFaviconDataReady, nsIFaviconDataCallback)
+  NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncWriteIconToDisk, nsIRunnable)
+  NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncDeleteIconFromDisk, nsIRunnable)
+  NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncDeleteAllFaviconsFromDisk, nsIRunnable)
+
+
+  const char FaviconHelper::kJumpListCacheDir[] = "jumpListCache";
+  const char FaviconHelper::kShortcutCacheDir[] = "shortcutCache";
+
 // SHCreateItemFromParsingName is only available on vista and up.
 WinUtils::SHCreateItemFromParsingNamePtr WinUtils::sCreateItemFromParsingName = nsnull;
 
 /* static */ 
 WinUtils::WinVersion
 WinUtils::GetWindowsVersion()
 {
   static PRInt32 version = 0;
@@ -362,16 +386,481 @@ HRESULT
 WinUtils::SHCreateItemFromParsingName(PCWSTR pszPath, IBindCtx *pbc,
                                       REFIID riid, void **ppv)
 {
   if (!VistaCreateItemFromParsingNameInit())
     return E_FAIL;
   return sCreateItemFromParsingName(pszPath, pbc, riid, ppv);
 }
 
+/************************************************************************/
+/* Constructs as AsyncFaviconDataReady Object
+/* @param aIOThread : the thread which performs the action
+/* @param aURLShortcut : Differentiates between (false)Jumplistcache and (true)Shortcutcache
+/************************************************************************/
+
+AsyncFaviconDataReady::AsyncFaviconDataReady(nsIURI *aNewURI, 
+                                             nsCOMPtr<nsIThread> &aIOThread, 
+                                             const bool aURLShortcut):
+  mNewURI(aNewURI),
+  mIOThread(aIOThread),
+  mURLShortcut(aURLShortcut)
+{
+}
+
+NS_IMETHODIMP
+myDownloadObserver::OnDownloadComplete(nsIDownloader *downloader, 
+                                     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);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<nsIURI> mozIconURI;
+  rv = NS_NewURI(getter_AddRefs(mozIconURI), "moz-icon://.html?size=32");
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+ 
+  nsCOMPtr<nsIChannel> channel;
+  rv = NS_NewChannel(getter_AddRefs(channel), mozIconURI);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<myDownloadObserver> downloadObserver = new myDownloadObserver;
+  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,
+                                  PRUint32 aDataLen,
+                                  const PRUint8 *aData, 
+                                  const nsACString &aMimeType)
+{
+  if (!aDataLen || !aData) {
+    if (mURLShortcut) {
+      OnFaviconDataNotAvailable();
+    }
+    return NS_OK;
+  }
+
+  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);
+
+  // 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();
+  PRUint8 *data = new (fallible) PRUint8[aDataLen];
+  if (!data) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  memcpy(data, aData, aDataLen);
+
+  //AsyncWriteIconToDisk takes ownership of the heap allocated buffer.
+  nsCOMPtr<nsIRunnable> event = new AsyncWriteIconToDisk(path, aMimeType, 
+                                                         data, 
+                                                         aDataLen,
+                                                         mURLShortcut);
+  mIOThread->Dispatch(event, NS_DISPATCH_NORMAL);
+
+  return NS_OK;
+}
+
+// Warning: AsyncWriteIconToDisk assumes ownership of the aData buffer passed in
+AsyncWriteIconToDisk::AsyncWriteIconToDisk(const nsAString &aIconPath,
+                                           const nsACString &aMimeTypeOfInputData,
+                                           PRUint8 *aBuffer, 
+                                           PRUint32 aBufferLength,
+                                           const bool aURLShortcut): 
+  mIconPath(aIconPath),
+  mMimeTypeOfInputData(aMimeTypeOfInputData),
+  mBuffer(aBuffer),
+  mBufferLength(aBufferLength),
+  mURLShortcut(aURLShortcut)
+
+{
+}
+
+NS_IMETHODIMP AsyncWriteIconToDisk::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) {
+    PRInt32 systemIconWidth = GetSystemMetrics(SM_CXSMICON);
+    PRInt32 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 {
+    mMimeTypeOfInputData.AssignLiteral("image/vnd.microsoft.icon");
+    rv = imgtool->EncodeImage(container, 
+                              mMimeTypeOfInputData,
+                              NS_LITERAL_STRING("format=bmp;bpp=32"),
+                              getter_AddRefs(iconStream));
+  }
+  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);
+
+  // Setup the output stream for the ICO file on disk
+  nsCOMPtr<nsIOutputStream> outputStream;
+  rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), icoFile);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Obtain the ICO buffer size from the re-encoded ICO stream
+  PRUint32 bufSize;
+  rv = iconStream->Available(&bufSize);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Setup a buffered output stream from the stream object
+  // so that we can simply use WriteFrom with the stream object
+  nsCOMPtr<nsIOutputStream> bufferedOutputStream;
+  rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
+                                  outputStream, bufSize);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Write out the icon stream to disk and make sure we wrote everything
+  PRUint32 wrote;
+  rv = bufferedOutputStream->WriteFrom(iconStream, bufSize, &wrote);
+  NS_ASSERTION(bufSize == wrote, 
+              "Icon wrote size should be equal to requested write size");
+
+  // Cleanup
+  bufferedOutputStream->Close();
+  outputStream->Close();
+  if (mURLShortcut) {
+    SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, SPI_SETNONCLIENTMETRICS, 0);
+  }
+  return rv;
+}
+
+AsyncWriteIconToDisk::~AsyncWriteIconToDisk()
+{
+}
+
+AsyncDeleteIconFromDisk::AsyncDeleteIconFromDisk(const nsAString &aIconPath)
+  : mIconPath(aIconPath)
+{
+}
+
+NS_IMETHODIMP AsyncDeleteIconFromDisk::Run()
+{
+  // Construct the parent path of the passed in path
+  nsCOMPtr<nsIFile> icoFile = do_CreateInstance("@mozilla.org/file/local;1");
+  NS_ENSURE_TRUE(icoFile, NS_ERROR_FAILURE);
+  nsresult rv = icoFile->InitWithPath(mIconPath);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Check if the cached ICO file exists
+  bool exists;
+  rv = icoFile->Exists(&exists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Check that we aren't deleting some arbitrary file that is not an icon
+  if (StringTail(mIconPath, 4).LowerCaseEqualsASCII(".ico")) {
+    // Check if the cached ICO file exists
+    bool exists;
+    if (NS_FAILED(icoFile->Exists(&exists)) || !exists)
+      return NS_ERROR_FAILURE;
+
+    // We found an ICO file that exists, so we should remove it
+    icoFile->Remove(false);
+  }
+
+  return NS_OK;
+}
+
+AsyncDeleteIconFromDisk::~AsyncDeleteIconFromDisk()
+{
+}
+
+AsyncDeleteAllFaviconsFromDisk::AsyncDeleteAllFaviconsFromDisk()
+{
+}
+
+NS_IMETHODIMP AsyncDeleteAllFaviconsFromDisk::Run()
+{
+  // Construct the path of our jump list cache
+  nsCOMPtr<nsIFile> jumpListCacheDir;
+  nsresult rv = NS_GetSpecialDirectory("ProfLDS", 
+    getter_AddRefs(jumpListCacheDir));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = jumpListCacheDir->AppendNative(
+      nsDependentCString(FaviconHelper::kJumpListCacheDir));
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsISimpleEnumerator> entries;
+  rv = jumpListCacheDir->GetDirectoryEntries(getter_AddRefs(entries));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Loop through each directory entry and remove all ICO files found
+  do {
+    bool hasMore = false;
+    if (NS_FAILED(entries->HasMoreElements(&hasMore)) || !hasMore)
+      break;
+
+    nsCOMPtr<nsISupports> supp;
+    if (NS_FAILED(entries->GetNext(getter_AddRefs(supp))))
+      break;
+
+    nsCOMPtr<nsIFile> currFile(do_QueryInterface(supp));
+    nsAutoString path;
+    if (NS_FAILED(currFile->GetPath(path)))
+      continue;
+
+    PRInt32 len = path.Length();
+    if (StringTail(path, 4).LowerCaseEqualsASCII(".ico")) {
+      // Check if the cached ICO file exists
+      bool exists;
+      if (NS_FAILED(currFile->Exists(&exists)) || !exists)
+        continue;
+
+      // We found an ICO file that exists, so we should remove it
+      currFile->Remove(false);
+    }
+  } while(true);
+
+  return NS_OK;
+}
+
+AsyncDeleteAllFaviconsFromDisk::~AsyncDeleteAllFaviconsFromDisk()
+{
+}
+
+
+/*
+ * (static) If the data is available, will return the path on disk where 
+ * the favicon for page aFaviconPageURI is stored.  If the favicon does not
+ * exist, or its cache is expired, this method will kick off an async request
+ * for the icon so that next time the method is called it will be available. 
+ * @param aFaviconPageURI The URI of the page to obtain
+ * @param aICOFilePath The path of the icon file
+ * @param aIOThread The thread to perform the Fetch on
+ * @param aURLShortcut to distinguish between jumplistcache(false) and shortcutcache(true)
+ */
+nsresult FaviconHelper::ObtainCachedIconFile(nsCOMPtr<nsIURI> aFaviconPageURI,
+                                             nsString &aICOFilePath,
+                                             nsCOMPtr<nsIThread> &aIOThread,
+                                             bool aURLShortcut)
+{
+  // Obtain the ICO file path
+  nsCOMPtr<nsIFile> icoFile;
+  nsresult rv = GetOutputIconPath(aFaviconPageURI, icoFile, aURLShortcut);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Check if the cached ICO file already exists
+  bool exists;
+  rv = icoFile->Exists(&exists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (exists) {
+
+    // Obtain the file's last modification date in seconds
+    PRInt64 fileModTime = LL_ZERO;
+    rv = icoFile->GetLastModifiedTime(&fileModTime);
+    fileModTime /= PR_MSEC_PER_SEC;
+    PRInt32 icoReCacheSecondsTimeout = GetICOCacheSecondsTimeout();
+    PRInt64 nowTime = PR_Now() / PRInt64(PR_USEC_PER_SEC);
+
+    // If the last mod call failed or the icon is old then re-cache it
+    // This check is in case the favicon of a page changes
+    // the next time we try to build the jump list, the data will be available.
+    if (NS_FAILED(rv) ||
+        (nowTime - fileModTime) > icoReCacheSecondsTimeout) {
+        CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread, aURLShortcut);
+        return NS_ERROR_NOT_AVAILABLE;
+    }
+  } else {
+
+    // The file does not exist yet, obtain it async from the favicon service so that
+    // the next time we try to build the jump list it'll be available.
+    CacheIconFileFromFaviconURIAsync(aFaviconPageURI, icoFile, aIOThread, aURLShortcut);
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  // The icoFile is filled with a path that exists, get its path
+  rv = icoFile->GetPath(aICOFilePath);
+  return rv;
+}
+
+nsresult FaviconHelper::HashURI(nsCOMPtr<nsICryptoHash> &aCryptoHash, 
+                                nsIURI *aUri, 
+                                nsACString& aUriHash)
+{
+  if (!aUri)
+    return NS_ERROR_INVALID_ARG;
+
+  nsCAutoString spec;
+  nsresult rv = aUri->GetSpec(spec);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!aCryptoHash) {
+    aCryptoHash = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  rv = aCryptoHash->Init(nsICryptoHash::MD5);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = aCryptoHash->Update(reinterpret_cast<const PRUint8*>(spec.BeginReading()), 
+                           spec.Length());
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = aCryptoHash->Finish(true, aUriHash);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+
+
+// (static) Obtains the ICO file for the favicon at page aFaviconPageURI
+// If successful, the file path on disk is in the format:
+// <ProfLDS>\jumpListCache\<hash(aFaviconPageURI)>.ico
+nsresult FaviconHelper::GetOutputIconPath(nsCOMPtr<nsIURI> aFaviconPageURI,
+  nsCOMPtr<nsIFile> &aICOFile,
+  bool aURLShortcut)
+{
+  // Hash the input URI and replace any / with _
+  nsCAutoString inputURIHash;
+  nsCOMPtr<nsICryptoHash> cryptoHash;
+  nsresult rv = HashURI(cryptoHash, aFaviconPageURI,
+                        inputURIHash);
+  NS_ENSURE_SUCCESS(rv, rv);
+  char* cur = inputURIHash.BeginWriting();
+  char* end = inputURIHash.EndWriting();
+  for (; cur < end; ++cur) {
+    if ('/' == *cur) {
+      *cur = '_';
+    }
+  }
+
+  // Obtain the local profile directory and construct the output icon file path
+  rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(aICOFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (!aURLShortcut)
+    rv = aICOFile->AppendNative(nsDependentCString(kJumpListCacheDir));
+  else
+    rv = aICOFile->AppendNative(nsDependentCString(kShortcutCacheDir));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Try to create the directory if it's not there yet
+  rv = aICOFile->Create(nsIFile::DIRECTORY_TYPE, 0777);
+  if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS) {
+    return rv;
+  }
+
+  // Append the icon extension
+  inputURIHash.Append(".ico");
+  rv = aICOFile->AppendNative(inputURIHash);
+
+  return rv;
+}
+
+// (static) Asynchronously creates a cached ICO file on disk for the favicon of
+// page aFaviconPageURI and stores it to disk at the path of aICOFile.
+nsresult 
+  FaviconHelper::CacheIconFileFromFaviconURIAsync(nsCOMPtr<nsIURI> aFaviconPageURI,
+                                                  nsCOMPtr<nsIFile> aICOFile,
+                                                  nsCOMPtr<nsIThread> &aIOThread,
+                                                  bool aURLShortcut)
+{
+  // Obtain the favicon service and get the favicon for the specified page
+  nsCOMPtr<mozIAsyncFavicons> favIconSvc(
+    do_GetService("@mozilla.org/browser/favicon-service;1"));
+  NS_ENSURE_TRUE(favIconSvc, NS_ERROR_FAILURE);
+
+  nsCOMPtr<nsIFaviconDataCallback> callback = 
+    new mozilla::widget::AsyncFaviconDataReady(aFaviconPageURI, 
+                                               aIOThread, 
+                                               aURLShortcut);
+
+  favIconSvc->GetFaviconDataForPage(aFaviconPageURI, callback);
+  return NS_OK;
+}
+
+// Obtains the jump list 'ICO cache timeout in seconds' pref
+PRInt32 FaviconHelper::GetICOCacheSecondsTimeout() {
+
+  // Only obtain the setting at most once from the pref service.
+  // In the rare case that 2 threads call this at the same
+  // time it is no harm and we will simply obtain the pref twice.
+  // None of the taskbar list prefs are currently updated via a
+  // pref observer so I think this should suffice.
+  const PRInt32 kSecondsPerDay = 86400;
+  static bool alreadyObtained = false;
+  static PRInt32 icoReCacheSecondsTimeout = kSecondsPerDay;
+  if (alreadyObtained) {
+    return icoReCacheSecondsTimeout;
+  }
+
+  // Obtain the pref
+  const char PREF_ICOTIMEOUT[]  = "browser.taskbar.lists.icoTimeoutInSeconds";
+  icoReCacheSecondsTimeout = Preferences::GetInt(PREF_ICOTIMEOUT, 
+                                                 kSecondsPerDay);
+  alreadyObtained = true;
+  return icoReCacheSecondsTimeout;
+}
+
+
+
+
 /* static */
 bool
 WinUtils::GetShellItemPath(IShellItem* aItem,
                            nsString& aResultString)
 {
   NS_ENSURE_TRUE(aItem, false);
   LPWSTR str = NULL;
   if (FAILED(aItem->GetDisplayName(SIGDN_FILESYSPATH, &str)))
--- a/widget/windows/WinUtils.h
+++ b/widget/windows/WinUtils.h
@@ -7,21 +7,34 @@
 #define mozilla_widget_WinUtils_h__
 
 #include "nscore.h"
 #include <windows.h>
 #include <shobjidl.h>
 #include "nsAutoPtr.h"
 #include "nsString.h"
 
+#include "nsThreadUtils.h"
+#include "nsICryptoHash.h"
+#include "nsIFaviconService.h" 
+#include "nsIDownloader.h"
+
+
 class nsWindow;
 
 namespace mozilla {
 namespace widget {
 
+class myDownloadObserver: public nsIDownloadObserver
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDOWNLOADOBSERVER
+};
+
 class WinUtils {
 public:
   enum WinVersion {
     WINXP_VERSION     = 0x501,
     WIN2K3_VERSION    = 0x502,
     VISTA_VERSION     = 0x600,
     // WIN2K8_VERSION    = VISTA_VERSION,
     WIN7_VERSION      = 0x601
@@ -198,12 +211,105 @@ private:
   /**
    * VistaCreateItemFromParsingNameInit() initializes the static pointer for
    * SHCreateItemFromParsingName() API which is usable only on Vista and later.
    * This returns TRUE if the API is available.  Otherwise, FALSE.
    */
   static bool VistaCreateItemFromParsingNameInit();
 };
 
+class AsyncFaviconDataReady : public nsIFaviconDataCallback
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIFAVICONDATACALLBACK
+  
+  AsyncFaviconDataReady(nsIURI *aNewURI, 
+                        nsCOMPtr<nsIThread> &aIOThread, 
+                        const bool aURLShortcut);
+  nsresult OnFaviconDataNotAvailable(void);
+private:
+  nsCOMPtr<nsIURI> mNewURI;
+  nsCOMPtr<nsIThread> mIOThread;
+  const bool mURLShortcut;
+};
+
+/**
+  * Asynchronously tries add the list to the build
+  */
+class AsyncWriteIconToDisk : 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,
+                       PRUint8 *aData, 
+                       PRUint32 aDataLen,
+                       const bool aURLShortcut);
+  virtual ~AsyncWriteIconToDisk();
+
+private:
+  nsAutoString mIconPath;
+  nsCAutoString mMimeTypeOfInputData;
+  nsAutoArrayPtr<PRUint8> mBuffer;
+  PRUint32 mBufferLength;
+};
+
+class AsyncDeleteIconFromDisk : public nsIRunnable
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIRUNNABLE
+
+  AsyncDeleteIconFromDisk(const nsAString &aIconPath);
+  virtual ~AsyncDeleteIconFromDisk();
+
+private:
+  nsAutoString mIconPath;
+};
+
+class AsyncDeleteAllFaviconsFromDisk : public nsIRunnable
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIRUNNABLE
+
+  AsyncDeleteAllFaviconsFromDisk();
+  virtual ~AsyncDeleteAllFaviconsFromDisk();
+};
+
+class FaviconHelper
+{
+public:
+  static const char kJumpListCacheDir[];
+  static const char kShortcutCacheDir[];
+  static nsresult ObtainCachedIconFile(nsCOMPtr<nsIURI> aFaviconPageURI,
+                                       nsString &aICOFilePath,
+                                       nsCOMPtr<nsIThread> &aIOThread,
+                                       bool aURLShortcut);
+
+  static nsresult HashURI(nsCOMPtr<nsICryptoHash> &aCryptoHash, 
+                          nsIURI *aUri,
+                          nsACString& aUriHash);
+
+  static nsresult GetOutputIconPath(nsCOMPtr<nsIURI> aFaviconPageURI,
+                                    nsCOMPtr<nsIFile> &aICOFile,
+                                    bool aURLShortcut);
+
+  static nsresult 
+  CacheIconFileFromFaviconURIAsync(nsCOMPtr<nsIURI> aFaviconPageURI,
+                                   nsCOMPtr<nsIFile> aICOFile,
+                                   nsCOMPtr<nsIThread> &aIOThread,
+                                   bool aURLShortcut);
+
+  static PRInt32 GetICOCacheSecondsTimeout();
+};
+
+
+
 } // namespace widget
 } // namespace mozilla
 
 #endif // mozilla_widget_WinUtils_h__
--- a/widget/windows/nsDataObj.cpp
+++ b/widget/windows/nsDataObj.cpp
@@ -25,18 +25,24 @@
 #include "nsNetUtil.h"
 #include "nsXPCOMStrings.h"
 #include "nscore.h"
 #include "prtypes.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsITimer.h"
 #include "nsThreadUtils.h"
 
+#include "WinUtils.h"
+#include "mozilla/LazyIdleThread.h"
+
+
 using namespace mozilla;
 
+#define DEFAULT_THREAD_TIMEOUT_MS 30000
+
 NS_IMPL_ISUPPORTS1(nsDataObj::CStream, nsIStreamListener)
 
 //-----------------------------------------------------------------------------
 // CStream implementation
 nsDataObj::CStream::CStream() :
   mChannelRead(false),
   mStreamRead(0)
 {
@@ -340,16 +346,19 @@ static GUID CLSID_nsDataObj =
 
 //-----------------------------------------------------
 // construction 
 //-----------------------------------------------------
 nsDataObj::nsDataObj(nsIURI * uri)
   : m_cRef(0), mTransferable(nsnull),
     mIsAsyncMode(FALSE), mIsInOperation(FALSE)
 {
+  mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS, 
+                                 NS_LITERAL_CSTRING("nsDataObj"),
+                                 LazyIdleThread::ManualShutdown);
   m_enumFE = new CEnumFormatEtc();
   m_enumFE->AddRef();
 
   if (uri) {
     // A URI was obtained, so pass this through to the DataObject
     // so it can create a SourceURL for CF_HTML flavour
     uri->GetSpec(mSourceURL);
   }
@@ -1083,37 +1092,54 @@ nsDataObj :: GetFileContentsInternetShor
 {
   nsAutoString url;
   if ( NS_FAILED(ExtractShortcutURL(url)) )
     return E_OUTOFMEMORY;
 
   // will need to change if we ever support iDNS
   nsCAutoString asciiUrl;
   LossyCopyUTF16toASCII(url, asciiUrl);
-    
-  static const char* shortcutFormatStr = "[InternetShortcut]\r\nURL=%s\r\n";
-  static const int formatLen = strlen(shortcutFormatStr) - 2; // don't include %s in the len
-  const int totalLen = formatLen + asciiUrl.Length(); // we don't want a null character on the end
+
+  nsCOMPtr<nsIFile> icoFile;
+  nsCOMPtr<nsIURI> aUri;
+  NS_NewURI(getter_AddRefs(aUri), url);
+
+  nsAutoString aUriHash;
+
+  mozilla::widget::FaviconHelper::ObtainCachedIconFile(aUri, aUriHash, mIOThread, true);
+
+  nsresult rv = mozilla::widget::FaviconHelper::GetOutputIconPath(aUri, icoFile, true);
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsCString path;
+  rv = icoFile->GetNativePath(path);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  static char* shortcutFormatStr = "[InternetShortcut]\r\nURL=%s\r\n" 
+                                   "IDList=\r\nHotKey=0\r\nIconFile=%s\r\n" 
+                                   "IconIndex=0\r\n";
+  static const int formatLen = strlen(shortcutFormatStr) - 2*2; // don't include %s (2 times) in the len
+  const int totalLen = formatLen + asciiUrl.Length() 
+                       + path.Length(); // we don't want a null character on the end
 
   // create a global memory area and build up the file contents w/in it
   HGLOBAL hGlobalMemory = ::GlobalAlloc(GMEM_SHARE, totalLen);
   if ( !hGlobalMemory )
     return E_OUTOFMEMORY;
 
   char* contents = reinterpret_cast<char*>(::GlobalLock(hGlobalMemory));
   if ( !contents ) {
     ::GlobalFree( hGlobalMemory );
     return E_OUTOFMEMORY;
   }
     
   //NOTE: we intentionally use the Microsoft version of snprintf here because it does NOT null 
   // terminate strings which reach the maximum size of the buffer. Since we know that the 
   // formatted length here is totalLen, this call to _snprintf will format the string into 
   // the buffer without appending the null character.
-  _snprintf( contents, totalLen, shortcutFormatStr, asciiUrl.get() );
+  _snprintf( contents, totalLen, shortcutFormatStr, asciiUrl.get(), path.get() );
     
   ::GlobalUnlock(hGlobalMemory);
   aSTG.hGlobal = hGlobalMemory;
   aSTG.tymed = TYMED_HGLOBAL;
 
   return S_OK;
 } // GetFileContentsInternetShortcut
 
--- a/widget/windows/nsDataObj.h
+++ b/widget/windows/nsDataObj.h
@@ -14,16 +14,18 @@
 #include "nsIFile.h"
 #include "nsIURI.h"
 #include "nsIInputStream.h"
 #include "nsIStreamListener.h"
 #include "nsIChannel.h"
 #include "nsCOMArray.h"
 #include "nsITimer.h"
 
+class nsIThread;
+
 // The SDK shipping with VC11 has renamed IAsyncOperation to
 // IDataObjectAsyncCapability.  We try to detect this, and rename this in our
 // code too to make sure that we pick the correct name when building.
 #ifdef __IDataObjectAsyncCapability_INTERFACE_DEFINED__
 #define IAsyncOperation IDataObjectAsyncCapability
 #define IID_IAsyncOperation IID_IDataObjectAsyncCapability
 #else
 // XXX for older version of PSDK where IAsyncOperation and related stuff is not available
@@ -80,16 +82,20 @@ class nsITransferable;
 /*
  * This ole registered class is used to facilitate drag-drop of objects which
  * can be adapted by an object derived from CfDragDrop. The CfDragDrop is
  * associated with instances via SetDragDrop().
  */
 class nsDataObj : public IDataObject,
                   public IAsyncOperation
 {
+
+protected:
+  nsCOMPtr<nsIThread> mIOThread;
+
   public: // construction, destruction
     nsDataObj(nsIURI *uri = nsnull);
     virtual ~nsDataObj();
 
 	public: // IUnknown methods - see iunknown.h for documentation
 		STDMETHODIMP_(ULONG) AddRef        ();
 		STDMETHODIMP 			QueryInterface(REFIID, void**);
 		STDMETHODIMP_(ULONG) Release       ();