Backout bug 622480 because of reftest failures on Windows debug
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 31 Mar 2011 11:00:53 -0400
changeset 64466 20e4d6f74a02c9ac0e8e976a4622bd25ab9a865c
parent 64452 ce53f5dd0092d187b810d65fe87fe39abad96a3a
child 64467 f34c27ea9f43c72618a33f0cf2a7d79e4945b8e6
push id19351
push usereakhgari@mozilla.com
push dateThu, 31 Mar 2011 15:02:59 +0000
treeherdermozilla-central@f34c27ea9f43 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs622480
milestone2.2a1pre
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
Backout bug 622480 because of reftest failures on Windows debug
modules/libpr0n/decoders/icon/win/nsIconChannel.cpp
modules/libpr0n/decoders/icon/win/nsIconChannel.h
--- a/modules/libpr0n/decoders/icon/win/nsIconChannel.cpp
+++ b/modules/libpr0n/decoders/icon/win/nsIconChannel.cpp
@@ -54,29 +54,28 @@
 #include "nsIURL.h"
 #include "nsNetUtil.h"
 #include "nsInt64.h"
 #include "nsIFile.h"
 #include "nsIFileURL.h"
 #include "nsIMIMEService.h"
 #include "nsCExternalHandlerService.h"
 #include "nsDirectoryServiceDefs.h"
-#include "nsAutoPtr.h"
-#include "nsThreadUtils.h"
-#include "nsProxyRelease.h"
-#include "mozilla/Mutex.h"
-#include "mozilla/CondVar.h"
 
 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
 #ifdef _WIN32_WINNT
 #undef _WIN32_WINNT
 #endif
 #define _WIN32_WINNT 0x0600
 #endif
 
+#ifdef WINCE
+#define SHGetFileInfoW SHGetFileInfo
+#endif
+
 // we need windows.h to read out registry information...
 #include <windows.h>
 #include <shellapi.h>
 #include <shlobj.h>
 #include <wchar.h>
 
 struct ICONFILEHEADER {
   PRUint16 ifhReserved;
@@ -90,560 +89,30 @@ struct ICONENTRY {
   PRUint8 ieColors;
   PRUint8 ieReserved;
   PRUint16 iePlanes;
   PRUint16 ieBitCount;
   PRUint32 ieSizeImage;
   PRUint32 ieFileOffset;
 };
 
-class ExtensionFetcherRunnable : public nsRunnable {
-  typedef mozilla::Mutex Mutex;
-  typedef mozilla::CondVar CondVar;
-public:
-  ExtensionFetcherRunnable(nsString& aFilePath,
-                           nsACString& aFileExt,
-                           nsACString& aContentType)
-    : mFilePath(aFilePath), mFileExt(aFileExt), mContentType(aContentType),
-      mLock("ExtensionFetcherRunnable"), mCondVar(mLock, "ExtensionFetcherRunnable"),
-      mSignaled(PR_FALSE)
-  { }
-
-  NS_IMETHOD Run()
-  {
-    mozilla::MutexAutoLock autoLock(mLock);
-
-    nsresult rv;
-    nsCOMPtr<nsIMIMEService> mimeService (do_GetService(NS_MIMESERVICE_CONTRACTID, &rv));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsCAutoString defFileExt;
-    mimeService->GetPrimaryExtension(mContentType, mFileExt, defFileExt);
-    // If the mime service does not know about this mime type, we show
-    // the generic icon.
-    // In any case, we need to insert a '.' before the extension.
-    mFilePath = NS_LITERAL_STRING(".") + NS_ConvertUTF8toUTF16(defFileExt);
-
-    // Notify the thread that created us that this call is complete
-    mSignaled = PR_TRUE;
-    mCondVar.Notify();
-
-    return NS_OK;
-  }
-
-  void Call() {
-    mozilla::MutexAutoLock autoLock(mLock);
-    NS_DispatchToMainThread(this);
-
-    while (!mSignaled)
-      mCondVar.Wait();
-  }
-private:
-  nsString& mFilePath;
-  const nsACString& mFileExt;
-  const nsACString& mContentType;
-  Mutex mLock;
-  CondVar mCondVar;
-  PRBool mSignaled;
-};
-
-// static helpers
 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
 typedef HRESULT (WINAPI*SHGetStockIconInfoPtr) (SHSTOCKICONID siid, UINT uFlags, SHSTOCKICONINFO *psii);
 
 // Match stock icons with names
 static SHSTOCKICONID GetStockIconIDForName(const nsACString &aStockName)
 {
   // UAC shield icon
   if (aStockName == NS_LITERAL_CSTRING("uac-shield"))
     return SIID_SHIELD;
 
   return SIID_INVALID;
 }
 #endif
 
-// Given a BITMAPINFOHEADER, returns the size of the color table.
-static int GetColorTableSize(BITMAPINFOHEADER* aHeader)
-{
-  int colorTableSize = -1;
-
-  // http://msdn.microsoft.com/en-us/library/dd183376%28v=VS.85%29.aspx
-  switch (aHeader->biBitCount) {
-  case 0:
-    colorTableSize = 0;
-    break;
-  case 1:
-    colorTableSize = 2 * sizeof(RGBQUAD);
-    break;
-  case 4:
-  case 8:
-  {
-    // The maximum possible size for the color table is 2**bpp, so check for
-    // that and fail if we're not in those bounds
-    unsigned int maxEntries = 1 << (aHeader->biBitCount);
-    if (aHeader->biClrUsed > 0 && aHeader->biClrUsed <= maxEntries)
-      colorTableSize = aHeader->biClrUsed * sizeof(RGBQUAD);
-    else if (aHeader->biClrUsed == 0)
-      colorTableSize = maxEntries * sizeof(RGBQUAD);
-    break;
-  }
-  case 16:
-  case 32:
-    if (aHeader->biCompression == BI_RGB)
-      colorTableSize = 0;
-    else if (aHeader->biCompression == BI_BITFIELDS)
-      colorTableSize = 3 * sizeof(DWORD);
-    break;
-  case 24:
-    colorTableSize = 0;
-    break;
-  }
-
-  if (colorTableSize < 0)
-    NS_WARNING("Unable to figure out the color table size for this bitmap");
-
-  return colorTableSize;
-}
-
-// Given a header and a size, creates a freshly allocated BITMAPINFO structure.
-// It is the caller's responsibility to null-check and delete the structure.
-static BITMAPINFO* CreateBitmapInfo(BITMAPINFOHEADER* aHeader,
-                                    size_t aColorTableSize)
-{
-  BITMAPINFO* bmi = (BITMAPINFO*) ::operator new(sizeof(BITMAPINFOHEADER) +
-                                                 aColorTableSize,
-                                                 mozilla::fallible_t());
-  if (bmi) {
-    memcpy(bmi, aHeader, sizeof(BITMAPINFOHEADER));
-    memset(bmi->bmiColors, 0, aColorTableSize);
-  }
-  return bmi;
-}
-
-static DWORD GetSpecialFolderIcon(nsIFile* aFile, int aFolder, SHFILEINFOW* aSFI, UINT aInfoFlags)
-{
-  NS_ABORT_IF_FALSE(!NS_IsMainThread(), "Shouldn't call shell functions on the main thread!");
-  DWORD shellResult = 0;
-
-  if (!aFile)
-    return shellResult;
-
-  PRUnichar fileNativePath[MAX_PATH];
-  nsAutoString fileNativePathStr;
-  aFile->GetPath(fileNativePathStr);
-  ::GetShortPathNameW(fileNativePathStr.get(), fileNativePath, NS_ARRAY_LENGTH(fileNativePath));
-
-  LPITEMIDLIST idList;
-  HRESULT hr = ::SHGetSpecialFolderLocation(NULL, aFolder, &idList);
-  if (SUCCEEDED(hr)) {
-    PRUnichar specialNativePath[MAX_PATH];
-    ::SHGetPathFromIDListW(idList, specialNativePath);
-    ::GetShortPathNameW(specialNativePath, specialNativePath, NS_ARRAY_LENGTH(specialNativePath));
-  
-    if (!wcsicmp(fileNativePath, specialNativePath)) {
-      aInfoFlags |= (SHGFI_PIDL | SHGFI_SYSICONINDEX);
-      shellResult = ::SHGetFileInfoW((LPCWSTR)(LPCITEMIDLIST)idList, 0, aSFI,
-                                     sizeof(*aSFI), aInfoFlags);
-      IMalloc* pMalloc;
-      hr = ::SHGetMalloc(&pMalloc);
-      if (SUCCEEDED(hr)) {
-        pMalloc->Free(idList);
-        pMalloc->Release();
-      }
-    }
-  }
-  return shellResult;
-}
-
-static UINT GetSizeInfoFlag(PRUint32 aDesiredImageSize)
-{
-  UINT infoFlag;
-  if (aDesiredImageSize > 16)
-    infoFlag = SHGFI_SHELLICONSIZE;
-  else
-    infoFlag = SHGFI_SMALLICON;
-
-  return infoFlag;
-}
-
-nsresult GetHIconFromFile(nsIMozIconURI* aIconURI, nsIFile* aFile, HICON *hIcon)
-{
-  NS_ABORT_IF_FALSE(!NS_IsMainThread(), "Shouldn't call shell functions on the main thread!");
-  nsresult rv;
-  nsXPIDLCString contentType;
-  aIconURI->GetContentType(contentType);
-  nsCString fileExt;
-  aIconURI->GetFileExtension(fileExt);
-  PRUint32 desiredImageSize;
-  aIconURI->GetImageSize(&desiredImageSize);
-
-  // if the file exists, we are going to use it's real attributes...otherwise we only want to use it for it's extension...
-  SHFILEINFOW      sfi;
-  UINT infoFlags = SHGFI_ICON;
-  
-  PRBool fileExists = PR_FALSE;
- 
-  nsAutoString filePath;
-  CopyASCIItoUTF16(fileExt, filePath);
-  if (aFile)
-  {
-    rv = aFile->Normalize();
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    aFile->GetPath(filePath);
-    if (filePath.Length() < 2 || filePath[1] != ':')
-      return NS_ERROR_MALFORMED_URI; // UNC
-
-    if (filePath.Last() == ':')
-      filePath.Append('\\');
-    else {
-      aFile->Exists(&fileExists);
-      if (!fileExists)
-       aFile->GetLeafName(filePath);
-    }
-  }
-
-  if (!fileExists)
-   infoFlags |= SHGFI_USEFILEATTRIBUTES;
-
-  infoFlags |= GetSizeInfoFlag(desiredImageSize);
-
-  // if we have a content type... then use it! but for existing files, we want
-  // to show their real icon.
-  if (!fileExists && !contentType.IsEmpty())
-  {
-    // NB: We need to call into the external app helper service on the main
-    // thread.
-    nsRefPtr<ExtensionFetcherRunnable> runnable =
-      new ExtensionFetcherRunnable(filePath, fileExt, contentType);
-    runnable->Call();
-  }
-
-  // Is this the "Desktop" folder?
-  DWORD shellResult = GetSpecialFolderIcon(aFile, CSIDL_DESKTOP, &sfi, infoFlags);
-  if (!shellResult) {
-    // Is this the "My Documents" folder?
-    shellResult = GetSpecialFolderIcon(aFile, CSIDL_PERSONAL, &sfi, infoFlags);
-  }
-
-  // There are other "Special Folders" and Namespace entities that we are not 
-  // fetching icons for, see: 
-  // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/enums/csidl.asp
-  // If we ever need to get them, code to do so would be inserted here. 
-
-  // Not a special folder, or something else failed above.
-  if (!shellResult)
-    shellResult = ::SHGetFileInfoW(filePath.get(),
-                                   FILE_ATTRIBUTE_ARCHIVE, &sfi, sizeof(sfi), infoFlags);
-
-  if (shellResult && sfi.hIcon)
-    *hIcon = sfi.hIcon;
-  else
-    rv = NS_ERROR_NOT_AVAILABLE;
-
-  return rv;
-}
-
-#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
-nsresult GetStockHIcon(nsIMozIconURI *aIconURI, HICON *hIcon)
-{
-  NS_ABORT_IF_FALSE(!NS_IsMainThread(), "Shouldn't call shell functions on the main thread!");
-  nsresult rv = NS_OK;
-
-  // We can only do this on Vista or above
-  HMODULE hShellDLL = ::LoadLibraryW(L"shell32.dll");
-  SHGetStockIconInfoPtr pSHGetStockIconInfo =
-    (SHGetStockIconInfoPtr) ::GetProcAddress(hShellDLL, "SHGetStockIconInfo");
-
-  if (pSHGetStockIconInfo)
-  {
-    PRUint32 desiredImageSize;
-    aIconURI->GetImageSize(&desiredImageSize);
-    nsCAutoString stockIcon;
-    aIconURI->GetStockIcon(stockIcon);
-
-    SHSTOCKICONID stockIconID = GetStockIconIDForName(stockIcon);
-    if (stockIconID == SIID_INVALID)
-      return NS_ERROR_NOT_AVAILABLE;
-
-    UINT infoFlags = SHGSI_ICON;
-    infoFlags |= GetSizeInfoFlag(desiredImageSize);
-
-    SHSTOCKICONINFO sii = {0};
-    sii.cbSize = sizeof(sii);
-    HRESULT hr = pSHGetStockIconInfo(stockIconID, infoFlags, &sii);
-
-    if (SUCCEEDED(hr))
-      *hIcon = sii.hIcon;
-    else
-      rv = NS_ERROR_FAILURE;
-  }
-  else
-  {
-    rv = NS_ERROR_NOT_AVAILABLE;
-  }
-
-  if (hShellDLL)
-    ::FreeLibrary(hShellDLL);
-
-  return rv;
-}
-#endif
-
-class nsIconInputStream : public nsIInputStream
-{
-public:
-  nsIconInputStream(nsIURI* aURI)
-    : mStatus(NS_OK)
-    , mInited(PR_FALSE)
-    , mSize(0)
-    , mAvailable(0)
-  {
-    nsresult rv;
-    NS_ABORT_IF_FALSE(NS_IsMainThread(), "Wrong thread");
-
-    // Clone the URI in case the main thread decides to modify it
-    nsCOMPtr<nsIURI> uri;
-    aURI->Clone(getter_AddRefs(uri));
-    mIconURI = do_QueryInterface(uri, &rv);
-    if (NS_FAILED(rv) || !mIconURI) return;
-
-    // We need to get the file on the main thread too since we can't QI
-    // the URI on the transport thread
-    nsCOMPtr<nsIURL> url;
-    rv = mIconURI->GetIconURL(getter_AddRefs(url));
-    if (NS_FAILED(rv) || !url) return;
-
-    nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(url, &rv);
-    if (NS_FAILED(rv) || !fileURL) return;
-
-    nsCOMPtr<nsIFile> file;
-    rv = fileURL->GetFile(getter_AddRefs(file));
-    if (NS_FAILED(rv) || !file) return;
-
-    rv = file->Clone(getter_AddRefs(mFile));
-	if (NS_FAILED(rv) || !mFile) return;
-  }
-
-  ~nsIconInputStream()
-  {
-    // Ensure that we Release the URI on the main thread
-    nsCOMPtr<nsIThread> mainThread(do_GetMainThread());
-    NS_ProxyRelease(mainThread, mIconURI);
-  }
-
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIINPUTSTREAM
-private:
-  PRBool IsClosed()
-  {
-    return NS_FAILED(mStatus);
-  }
-
-  nsresult Init();
-
-  nsresult mStatus;
-  PRBool mInited;
-  PRUint32 mSize;
-  PRUint32 mAvailable;
-  nsCOMPtr<nsIMozIconURI> mIconURI;
-  nsCOMPtr<nsIFile> mFile;
-  nsAutoArrayPtr<char> mBuffer;
-};
-
-nsresult
-nsIconInputStream::Init()
-{
-  mInited = PR_TRUE;
-  NS_ENSURE_TRUE(mIconURI, NS_ERROR_FAILURE);
-
-  // Check whether the icon requested's a file icon or a stock icon
-  nsresult rv = NS_ERROR_NOT_AVAILABLE;
-
-  // GetDIBits does not exist on windows mobile.
-  HICON hIcon = NULL;
-
-#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
-  nsCAutoString stockIcon;
-  mIconURI->GetStockIcon(stockIcon);
-  if (!stockIcon.IsEmpty())
-    rv = GetStockHIcon(mIconURI, &hIcon);
-  else
-#endif
-    rv = GetHIconFromFile(mIconURI, mFile, &hIcon);
-
-  if (!NS_SUCCEEDED(rv)) {
-    mStatus = rv;
-	return rv;
-  }
-
-  if (hIcon)
-  {
-    // we got a handle to an icon. Now we want to get a bitmap for the icon using GetIconInfo....
-    ICONINFO iconInfo;
-    if (GetIconInfo(hIcon, &iconInfo))
-    {
-      // we got the bitmaps, first find out their size
-      HDC hDC = CreateCompatibleDC(NULL); // get a device context for the screen.
-      BITMAPINFOHEADER maskHeader  = {sizeof(BITMAPINFOHEADER)};
-      BITMAPINFOHEADER colorHeader = {sizeof(BITMAPINFOHEADER)};
-      int colorTableSize, maskTableSize;
-      if (GetDIBits(hDC, iconInfo.hbmMask,  0, 0, NULL, (BITMAPINFO*)&maskHeader,  DIB_RGB_COLORS) &&
-          GetDIBits(hDC, iconInfo.hbmColor, 0, 0, NULL, (BITMAPINFO*)&colorHeader, DIB_RGB_COLORS) &&
-          maskHeader.biHeight == colorHeader.biHeight &&
-          maskHeader.biWidth  == colorHeader.biWidth  &&
-          colorHeader.biBitCount > 8 &&
-          colorHeader.biSizeImage > 0 &&
-          maskHeader.biSizeImage > 0  &&
-          (colorTableSize = GetColorTableSize(&colorHeader)) >= 0 &&
-          (maskTableSize  = GetColorTableSize(&maskHeader))  >= 0) {
-        mSize = sizeof(ICONFILEHEADER) +
-                sizeof(ICONENTRY) +
-                sizeof(BITMAPINFOHEADER) +
-                colorHeader.biSizeImage +
-                maskHeader.biSizeImage;
-
-        // Fallible malloc is ugly
-		mBuffer = (char*) ::operator new(mSize,
-		                                 mozilla::fallible_t());
-        if (!mBuffer) {
-          rv = NS_ERROR_OUT_OF_MEMORY;
-        } else {
-          char *whereTo = mBuffer;
-          int howMuch;
-
-          // the data starts with an icon file header
-          ICONFILEHEADER iconHeader;
-          iconHeader.ifhReserved = 0;
-          iconHeader.ifhType = 1;
-          iconHeader.ifhCount = 1;
-          howMuch = sizeof(ICONFILEHEADER);
-          memcpy(whereTo, &iconHeader, howMuch);
-          whereTo += howMuch;
-
-          // followed by the single icon entry
-          ICONENTRY iconEntry;
-          iconEntry.ieWidth = colorHeader.biWidth;
-          iconEntry.ieHeight = colorHeader.biHeight;
-          iconEntry.ieColors = 0;
-          iconEntry.ieReserved = 0;
-          iconEntry.iePlanes = 1;
-          iconEntry.ieBitCount = colorHeader.biBitCount;
-          iconEntry.ieSizeImage = sizeof(BITMAPINFOHEADER) +
-                                  colorHeader.biSizeImage +
-                                  maskHeader.biSizeImage;
-          iconEntry.ieFileOffset = sizeof(ICONFILEHEADER) + sizeof(ICONENTRY);
-          howMuch = sizeof(ICONENTRY);
-          memcpy(whereTo, &iconEntry, howMuch);
-          whereTo += howMuch;
-
-          // followed by the bitmap info header
-          // (doubling the height because icons have two bitmaps)
-          colorHeader.biHeight *= 2;
-          colorHeader.biSizeImage += maskHeader.biSizeImage;
-          howMuch = sizeof(BITMAPINFOHEADER);
-          memcpy(whereTo, &colorHeader, howMuch);
-          whereTo += howMuch;
-          colorHeader.biHeight /= 2;
-          colorHeader.biSizeImage -= maskHeader.biSizeImage;
-
-          // followed by the XOR bitmap data (colorHeader)
-          // (you'd expect the color table to come here, but it apparently doesn't)
-          BITMAPINFO* colorInfo = CreateBitmapInfo(&colorHeader, colorTableSize);
-          if (colorInfo && GetDIBits(hDC, iconInfo.hbmColor, 0,
-                                     colorHeader.biHeight, whereTo, colorInfo,
-                                     DIB_RGB_COLORS)) {
-            whereTo += colorHeader.biSizeImage;
-
-            // and finally the AND bitmap data (maskHeader)
-            BITMAPINFO* maskInfo = CreateBitmapInfo(&maskHeader, maskTableSize);
-            if (maskInfo && GetDIBits(hDC, iconInfo.hbmMask, 0,
-                                      maskHeader.biHeight, whereTo, maskInfo,
-                                      DIB_RGB_COLORS)) {
-              rv = NS_OK; // We succeeded
-            } // if we got bitmap bits
-            delete maskInfo;
-          } // if we got mask bits
-          delete colorInfo;
-          mAvailable = mSize;
-        } // if we allocated the buffer
-      } // if we got mask size
-
-      DeleteDC(hDC);
-      DeleteObject(iconInfo.hbmColor);
-      DeleteObject(iconInfo.hbmMask);
-    } // if we got icon info
-    DestroyIcon(hIcon);
-  } // if we got an hIcon
-
-  mStatus = rv;
-  return rv;
-}
-
-NS_IMPL_THREADSAFE_ISUPPORTS1(nsIconInputStream, nsIInputStream)
-
-// nsIconInputStream::nsIInputStream
-NS_IMETHODIMP
-nsIconInputStream::Close()
-{
-  if (IsClosed())
-    return NS_OK;
-
-  mBuffer = nsnull; // Free our buffer if any
-  return mStatus = NS_BASE_STREAM_CLOSED; // Set our status and return it
-}
-
-NS_IMETHODIMP
-nsIconInputStream::Available(PRUint32 *result)
-{
-  if (!mInited)
-    Init();
-
-  if (IsClosed())
-    return mStatus;
-
-  return mAvailable;
-}
-
-NS_IMETHODIMP
-nsIconInputStream::Read(char *buf, PRUint32 count, PRUint32 *result)
-{
-  if (mStatus == NS_BASE_STREAM_CLOSED)
-    return NS_OK;
-
-  if (IsClosed())
-    return mStatus;
-
-  if (!mInited)
-    Init();
-
-  // Check this again to see if init failed
-  if (IsClosed())
-    return mStatus;
-
-  *result = NS_MIN(count, mAvailable);
-  memcpy(buf, mBuffer + (mSize - mAvailable), *result);
-  mAvailable -= *result;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsIconInputStream::ReadSegments(nsWriteSegmentFun fun, void *closure,
-                                PRUint32 count, PRUint32 *result)
-{
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsIconInputStream::IsNonBlocking(PRBool *result)
-{
-  *result = PR_FALSE;
-  return NS_OK;
-}
-
 // nsIconChannel methods
 nsIconChannel::nsIconChannel()
 {
 }
 
 nsIconChannel::~nsIconChannel() 
 {}
 
@@ -740,23 +209,47 @@ NS_IMETHODIMP nsIconChannel::GetURI(nsIU
   *aURI = mUrl;
   NS_IF_ADDREF(*aURI);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsIconChannel::Open(nsIInputStream **_retval)
 {
-  return MakeInputStream(_retval);
+  return MakeInputStream(_retval, PR_FALSE);
+}
+
+nsresult nsIconChannel::ExtractIconInfoFromUrl(nsIFile ** aLocalFile, PRUint32 * aDesiredImageSize, nsCString &aContentType, nsCString &aFileExtension)
+{
+  nsresult rv = NS_OK;
+  nsCOMPtr<nsIMozIconURI> iconURI (do_QueryInterface(mUrl, &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  iconURI->GetImageSize(aDesiredImageSize);
+  iconURI->GetContentType(aContentType);
+  iconURI->GetFileExtension(aFileExtension);
+
+  nsCOMPtr<nsIURL> url;
+  rv = iconURI->GetIconURL(getter_AddRefs(url));
+  if (NS_FAILED(rv) || !url) return NS_OK;
+
+  nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(url, &rv);
+  if (NS_FAILED(rv) || !fileURL) return NS_OK;
+
+  nsCOMPtr<nsIFile> file;
+  rv = fileURL->GetFile(getter_AddRefs(file));
+  if (NS_FAILED(rv) || !file) return NS_OK;
+
+  return file->Clone(aLocalFile);
 }
 
 NS_IMETHODIMP nsIconChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt)
 {
   nsCOMPtr<nsIInputStream> inStream;
-  nsresult rv = MakeInputStream(getter_AddRefs(inStream));
+  nsresult rv = MakeInputStream(getter_AddRefs(inStream), PR_TRUE);
   if (NS_FAILED(rv))
     return rv;
 
   // Init our streampump
   rv = mPump->Init(inStream, nsInt64(-1), nsInt64(-1), 0, 0, PR_FALSE);
   if (NS_FAILED(rv))
     return rv;
 
@@ -766,22 +259,484 @@ NS_IMETHODIMP nsIconChannel::AsyncOpen(n
     mListener = aListener;
     // Add ourself to the load group, if available
     if (mLoadGroup)
       mLoadGroup->AddRequest(this, nsnull);
   }
   return rv;
 }
 
-nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval)
+#ifndef WINCE
+static DWORD GetSpecialFolderIcon(nsIFile* aFile, int aFolder, SHFILEINFOW* aSFI, UINT aInfoFlags)
+{
+  DWORD shellResult = 0;
+
+  if (!aFile)
+    return shellResult;
+
+  PRUnichar fileNativePath[MAX_PATH];
+  nsAutoString fileNativePathStr;
+  aFile->GetPath(fileNativePathStr);
+  ::GetShortPathNameW(fileNativePathStr.get(), fileNativePath, NS_ARRAY_LENGTH(fileNativePath));
+
+  LPITEMIDLIST idList;
+  HRESULT hr = ::SHGetSpecialFolderLocation(NULL, aFolder, &idList);
+  if (SUCCEEDED(hr)) {
+    PRUnichar specialNativePath[MAX_PATH];
+    ::SHGetPathFromIDListW(idList, specialNativePath);
+    ::GetShortPathNameW(specialNativePath, specialNativePath, NS_ARRAY_LENGTH(specialNativePath));
+  
+    if (!wcsicmp(fileNativePath, specialNativePath)) {
+      aInfoFlags |= (SHGFI_PIDL | SHGFI_SYSICONINDEX);
+      shellResult = ::SHGetFileInfoW((LPCWSTR)(LPCITEMIDLIST)idList, 0, aSFI,
+                                     sizeof(*aSFI), aInfoFlags);
+      IMalloc* pMalloc;
+      hr = ::SHGetMalloc(&pMalloc);
+      if (SUCCEEDED(hr)) {
+        pMalloc->Free(idList);
+        pMalloc->Release();
+      }
+    }
+  }
+  return shellResult;
+}
+#endif
+
+static UINT GetSizeInfoFlag(PRUint32 aDesiredImageSize)
+{
+  UINT infoFlag;
+  if (aDesiredImageSize > 16)
+#ifndef WINCE
+    infoFlag = SHGFI_SHELLICONSIZE;
+#else
+    infoFlag = SHGFI_LARGEICON;
+#endif
+  else
+    infoFlag = SHGFI_SMALLICON;
+
+  return infoFlag;
+}
+
+nsresult nsIconChannel::GetHIconFromFile(HICON *hIcon)
 {
-  nsRefPtr<nsIconInputStream> stream = new nsIconInputStream(mUrl);
-  return CallQueryInterface(stream, _retval);
+#ifdef WINCE_WINDOWS_MOBILE
+    // GetDIBits does not exist on windows mobile.
+  return NS_ERROR_NOT_AVAILABLE;
+#else
+  nsXPIDLCString contentType;
+  nsCString fileExt;
+  nsCOMPtr<nsIFile> localFile; // file we want an icon for
+  PRUint32 desiredImageSize;
+  nsresult rv = ExtractIconInfoFromUrl(getter_AddRefs(localFile), &desiredImageSize, contentType, fileExt);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // if the file exists, we are going to use it's real attributes...otherwise we only want to use it for it's extension...
+  SHFILEINFOW      sfi;
+  UINT infoFlags = SHGFI_ICON;
+  
+  PRBool fileExists = PR_FALSE;
+ 
+  nsAutoString filePath;
+  CopyASCIItoUTF16(fileExt, filePath);
+  if (localFile)
+  {
+    rv = localFile->Normalize();
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    localFile->GetPath(filePath);
+#ifndef WINCE
+    if (filePath.Length() < 2 || filePath[1] != ':')
+      return NS_ERROR_MALFORMED_URI; // UNC
+#else
+    // WinCE paths don't have drive letters
+    if (filePath.Length() < 2 ||
+        filePath[0] != '\\' || filePath[1] == '\\')
+      return NS_ERROR_MALFORMED_URI; // UNC
+#endif
+
+    if (filePath.Last() == ':')
+      filePath.Append('\\');
+    else {
+      localFile->Exists(&fileExists);
+      if (!fileExists)
+       localFile->GetLeafName(filePath);
+    }
+  }
+
+  if (!fileExists)
+   infoFlags |= SHGFI_USEFILEATTRIBUTES;
+
+  infoFlags |= GetSizeInfoFlag(desiredImageSize);
+
+  // if we have a content type... then use it! but for existing files, we want
+  // to show their real icon.
+  if (!fileExists && !contentType.IsEmpty())
+  {
+    nsCOMPtr<nsIMIMEService> mimeService (do_GetService(NS_MIMESERVICE_CONTRACTID, &rv));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    nsCAutoString defFileExt;
+    mimeService->GetPrimaryExtension(contentType, fileExt, defFileExt);
+    // If the mime service does not know about this mime type, we show
+    // the generic icon.
+    // In any case, we need to insert a '.' before the extension.
+    filePath = NS_LITERAL_STRING(".") + NS_ConvertUTF8toUTF16(defFileExt);
+  }
+
+#ifndef WINCE
+  // Is this the "Desktop" folder?
+  DWORD shellResult = GetSpecialFolderIcon(localFile, CSIDL_DESKTOP, &sfi, infoFlags);
+  if (!shellResult) {
+    // Is this the "My Documents" folder?
+    shellResult = GetSpecialFolderIcon(localFile, CSIDL_PERSONAL, &sfi, infoFlags);
+  }
+#else
+  DWORD shellResult = 0;
+  // Fantastic. On WinCE, ::SHGetFileInfo (with a localFile) fails
+  // unless I also set another flag like this. We don't actually need
+  // the display name.
+  if (localFile)
+    infoFlags |= SHGFI_DISPLAYNAME;
+#endif
+
+  // There are other "Special Folders" and Namespace entities that we are not 
+  // fetching icons for, see: 
+  // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/enums/csidl.asp
+  // If we ever need to get them, code to do so would be inserted here. 
+
+  // Not a special folder, or something else failed above.
+  if (!shellResult)
+    shellResult = ::SHGetFileInfoW(filePath.get(),
+                                   FILE_ATTRIBUTE_ARCHIVE, &sfi, sizeof(sfi), infoFlags);
+
+  if (shellResult && sfi.hIcon)
+    *hIcon = sfi.hIcon;
+  else
+    rv = NS_ERROR_NOT_AVAILABLE;
+
+  return rv;
+#endif
 }
 
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
+nsresult nsIconChannel::GetStockHIcon(nsIMozIconURI *aIconURI, HICON *hIcon)
+{
+  nsresult rv = NS_OK;
+
+  // We can only do this on Vista or above
+  HMODULE hShellDLL = ::LoadLibraryW(L"shell32.dll");
+  SHGetStockIconInfoPtr pSHGetStockIconInfo =
+    (SHGetStockIconInfoPtr) ::GetProcAddress(hShellDLL, "SHGetStockIconInfo");
+
+  if (pSHGetStockIconInfo)
+  {
+    PRUint32 desiredImageSize;
+    aIconURI->GetImageSize(&desiredImageSize);
+    nsCAutoString stockIcon;
+    aIconURI->GetStockIcon(stockIcon);
+
+    SHSTOCKICONID stockIconID = GetStockIconIDForName(stockIcon);
+    if (stockIconID == SIID_INVALID)
+      return NS_ERROR_NOT_AVAILABLE;
+
+    UINT infoFlags = SHGSI_ICON;
+    infoFlags |= GetSizeInfoFlag(desiredImageSize);
+
+    SHSTOCKICONINFO sii = {0};
+    sii.cbSize = sizeof(sii);
+    HRESULT hr = pSHGetStockIconInfo(stockIconID, infoFlags, &sii);
+
+    if (SUCCEEDED(hr))
+      *hIcon = sii.hIcon;
+    else
+      rv = NS_ERROR_FAILURE;
+  }
+  else
+  {
+    rv = NS_ERROR_NOT_AVAILABLE;
+  }
+
+  if (hShellDLL)
+    ::FreeLibrary(hShellDLL);
+
+  return rv;
+}
+#endif
+
+#ifdef WINCE
+int GetDIBits(HDC hdc,
+              HBITMAP hbmp,
+              UINT uStartScan,
+              UINT cScanLines,
+              LPVOID lpvBits,
+              LPBITMAPINFO lpbi,
+              UINT uUsage)
+{
+  // Enforce some assumptions this simplified implementation makes
+  if (!hdc || !hbmp || uStartScan != 0 ||
+      !lpbi || uUsage != DIB_RGB_COLORS ||
+      lpvBits == NULL && lpbi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER))
+    return 0;
+
+  BITMAP bmpInfo;
+  if (!::GetObject(hbmp, sizeof(BITMAP), &bmpInfo))
+    return 0;
+
+  lpbi->bmiHeader.biWidth         = bmpInfo.bmWidth;
+  lpbi->bmiHeader.biHeight        = bmpInfo.bmHeight;
+  lpbi->bmiHeader.biPlanes        = bmpInfo.bmPlanes;
+  lpbi->bmiHeader.biBitCount      = bmpInfo.bmBitsPixel;
+  lpbi->bmiHeader.biCompression   = BI_RGB; // 0
+  lpbi->bmiHeader.biSizeImage     = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+  lpbi->bmiHeader.biXPelsPerMeter = 0;
+  lpbi->bmiHeader.biYPelsPerMeter = 0;
+  lpbi->bmiHeader.biClrUsed       = 0;
+  lpbi->bmiHeader.biClrImportant  = 0;
+
+  if (lpbi->bmiHeader.biBitCount == 1) {
+    // Need to set this or else the mask is inverted.
+    lpbi->bmiHeader.biClrUsed       = 2;
+    lpbi->bmiHeader.biClrImportant  = 2;
+    lpbi->bmiColors[0].rgbRed = lpbi->bmiColors[0].rgbGreen =
+      lpbi->bmiColors[0].rgbBlue = lpbi->bmiColors[0].rgbReserved = 0;
+    lpbi->bmiColors[1].rgbRed = lpbi->bmiColors[1].rgbGreen =
+      lpbi->bmiColors[1].rgbBlue = lpbi->bmiColors[1].rgbReserved = 255;
+  }
+
+  if (lpvBits == NULL)
+    return bmpInfo.bmHeight;
+
+  // We just want to pull out the image bits, but Windows CE makes
+  // this stupidly difficult to do...
+  HBITMAP hTargetBitmap;
+  void *pBuffer; 
+  HDC someDC = ::GetDC(NULL);
+  hTargetBitmap = ::CreateDIBSection(someDC, lpbi, DIB_RGB_COLORS,
+                                     (void**)&pBuffer, NULL, 0);
+  ::ReleaseDC(NULL, someDC);
+
+  HDC memDc    = ::CreateCompatibleDC(NULL);
+  HDC targetDc = ::CreateCompatibleDC(NULL);
+  if (!memDc || !targetDc)
+    return 0;
+
+  HBITMAP hOldMemBitmap = (HBITMAP)::SelectObject(memDc, hbmp);
+  HBITMAP hOldTgtBitmap = (HBITMAP)::SelectObject(targetDc, hTargetBitmap);
+
+  // BitBlt into the target bitmap, then copy the bits into our buffer.
+  ::BitBlt(targetDc, 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, memDc, 0, 0, SRCCOPY);
+  memcpy(lpvBits, pBuffer, lpbi->bmiHeader.biSizeImage);
+
+  // Cleanup
+  ::SelectObject(memDc, hOldMemBitmap);
+  ::SelectObject(targetDc, hOldTgtBitmap);
+  ::DeleteDC(memDc);
+  ::DeleteDC(targetDc); 
+  ::DeleteObject(hTargetBitmap); 
+
+  return bmpInfo.bmHeight;
+}
+#endif
+
+// Given a BITMAPINFOHEADER, returns the size of the color table.
+static int GetColorTableSize(BITMAPINFOHEADER* aHeader)
+{
+  int colorTableSize = -1;
+
+  // http://msdn.microsoft.com/en-us/library/dd183376%28v=VS.85%29.aspx
+  switch (aHeader->biBitCount) {
+  case 0:
+    colorTableSize = 0;
+    break;
+  case 1:
+    colorTableSize = 2 * sizeof(RGBQUAD);
+    break;
+  case 4:
+  case 8:
+  {
+    // The maximum possible size for the color table is 2**bpp, so check for
+    // that and fail if we're not in those bounds
+    unsigned int maxEntries = 1 << (aHeader->biBitCount);
+    if (aHeader->biClrUsed > 0 && aHeader->biClrUsed <= maxEntries)
+      colorTableSize = aHeader->biClrUsed * sizeof(RGBQUAD);
+    else if (aHeader->biClrUsed == 0)
+      colorTableSize = maxEntries * sizeof(RGBQUAD);
+    break;
+  }
+  case 16:
+  case 32:
+    if (aHeader->biCompression == BI_RGB)
+      colorTableSize = 0;
+    else if (aHeader->biCompression == BI_BITFIELDS)
+      colorTableSize = 3 * sizeof(DWORD);
+    break;
+  case 24:
+    colorTableSize = 0;
+    break;
+  }
+
+  if (colorTableSize < 0)
+    NS_WARNING("Unable to figure out the color table size for this bitmap");
+
+  return colorTableSize;
+}
+
+// Given a header and a size, creates a freshly allocated BITMAPINFO structure.
+// It is the caller's responsibility to null-check and delete the structure.
+static BITMAPINFO* CreateBitmapInfo(BITMAPINFOHEADER* aHeader,
+                                    size_t aColorTableSize)
+{
+  BITMAPINFO* bmi = (BITMAPINFO*) ::operator new(sizeof(BITMAPINFOHEADER) +
+                                                 aColorTableSize,
+                                                 mozilla::fallible_t());
+  if (bmi) {
+    memcpy(bmi, aHeader, sizeof(BITMAPINFOHEADER));
+    memset(bmi->bmiColors, 0, aColorTableSize);
+  }
+  return bmi;
+}
+
+nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, PRBool nonBlocking)
+{
+  // Check whether the icon requested's a file icon or a stock icon
+  nsresult rv = NS_ERROR_NOT_AVAILABLE;
+
+  // GetDIBits does not exist on windows mobile.
+#ifndef WINCE_WINDOWS_MOBILE
+  HICON hIcon = NULL;
+
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
+  nsCOMPtr<nsIMozIconURI> iconURI(do_QueryInterface(mUrl, &rv));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCAutoString stockIcon;
+  iconURI->GetStockIcon(stockIcon);
+  if (!stockIcon.IsEmpty())
+    rv = GetStockHIcon(iconURI, &hIcon);
+  else
+#endif
+    rv = GetHIconFromFile(&hIcon);
+
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (hIcon)
+  {
+    // we got a handle to an icon. Now we want to get a bitmap for the icon using GetIconInfo....
+    ICONINFO iconInfo;
+    if (GetIconInfo(hIcon, &iconInfo))
+    {
+      // we got the bitmaps, first find out their size
+      HDC hDC = CreateCompatibleDC(NULL); // get a device context for the screen.
+      BITMAPINFOHEADER maskHeader  = {sizeof(BITMAPINFOHEADER)};
+      BITMAPINFOHEADER colorHeader = {sizeof(BITMAPINFOHEADER)};
+      int colorTableSize, maskTableSize;
+      if (GetDIBits(hDC, iconInfo.hbmMask,  0, 0, NULL, (BITMAPINFO*)&maskHeader,  DIB_RGB_COLORS) &&
+          GetDIBits(hDC, iconInfo.hbmColor, 0, 0, NULL, (BITMAPINFO*)&colorHeader, DIB_RGB_COLORS) &&
+          maskHeader.biHeight == colorHeader.biHeight &&
+          maskHeader.biWidth  == colorHeader.biWidth  &&
+          colorHeader.biBitCount > 8 &&
+          colorHeader.biSizeImage > 0 &&
+          maskHeader.biSizeImage > 0  &&
+          (colorTableSize = GetColorTableSize(&colorHeader)) >= 0 &&
+          (maskTableSize  = GetColorTableSize(&maskHeader))  >= 0) {
+        PRUint32 iconSize = sizeof(ICONFILEHEADER) +
+                            sizeof(ICONENTRY) +
+                            sizeof(BITMAPINFOHEADER) +
+                            colorHeader.biSizeImage +
+                            maskHeader.biSizeImage;
+
+        char *buffer = new char[iconSize];
+        if (!buffer)
+          rv = NS_ERROR_OUT_OF_MEMORY;
+        else {
+          char *whereTo = buffer;
+          int howMuch;
+
+          // the data starts with an icon file header
+          ICONFILEHEADER iconHeader;
+          iconHeader.ifhReserved = 0;
+          iconHeader.ifhType = 1;
+          iconHeader.ifhCount = 1;
+          howMuch = sizeof(ICONFILEHEADER);
+          memcpy(whereTo, &iconHeader, howMuch);
+          whereTo += howMuch;
+
+          // followed by the single icon entry
+          ICONENTRY iconEntry;
+          iconEntry.ieWidth = colorHeader.biWidth;
+          iconEntry.ieHeight = colorHeader.biHeight;
+          iconEntry.ieColors = 0;
+          iconEntry.ieReserved = 0;
+          iconEntry.iePlanes = 1;
+          iconEntry.ieBitCount = colorHeader.biBitCount;
+          iconEntry.ieSizeImage = sizeof(BITMAPINFOHEADER) +
+                                  colorHeader.biSizeImage +
+                                  maskHeader.biSizeImage;
+          iconEntry.ieFileOffset = sizeof(ICONFILEHEADER) + sizeof(ICONENTRY);
+          howMuch = sizeof(ICONENTRY);
+          memcpy(whereTo, &iconEntry, howMuch);
+          whereTo += howMuch;
+
+          // followed by the bitmap info header
+          // (doubling the height because icons have two bitmaps)
+          colorHeader.biHeight *= 2;
+          colorHeader.biSizeImage += maskHeader.biSizeImage;
+          howMuch = sizeof(BITMAPINFOHEADER);
+          memcpy(whereTo, &colorHeader, howMuch);
+          whereTo += howMuch;
+          colorHeader.biHeight /= 2;
+          colorHeader.biSizeImage -= maskHeader.biSizeImage;
+
+          // followed by the XOR bitmap data (colorHeader)
+          // (you'd expect the color table to come here, but it apparently doesn't)
+          BITMAPINFO* colorInfo = CreateBitmapInfo(&colorHeader, colorTableSize);
+          if (colorInfo && GetDIBits(hDC, iconInfo.hbmColor, 0,
+                                     colorHeader.biHeight, whereTo, colorInfo,
+                                     DIB_RGB_COLORS)) {
+            whereTo += colorHeader.biSizeImage;
+
+            // and finally the AND bitmap data (maskHeader)
+            BITMAPINFO* maskInfo = CreateBitmapInfo(&maskHeader, maskTableSize);
+            if (maskInfo && GetDIBits(hDC, iconInfo.hbmMask, 0,
+                                      maskHeader.biHeight, whereTo, maskInfo,
+                                      DIB_RGB_COLORS)) {
+              // Now, create a pipe and stuff our data into it
+              nsCOMPtr<nsIInputStream> inStream;
+              nsCOMPtr<nsIOutputStream> outStream;
+              rv = NS_NewPipe(getter_AddRefs(inStream), getter_AddRefs(outStream),
+                              iconSize, iconSize, nonBlocking);
+              if (NS_SUCCEEDED(rv)) {
+                PRUint32 written;
+                rv = outStream->Write(buffer, iconSize, &written);
+                if (NS_SUCCEEDED(rv)) {
+                  NS_ADDREF(*_retval = inStream);
+                }
+              }
+
+            } // if we got bitmap bits
+            delete maskInfo;
+          } // if we got mask bits
+          delete colorInfo;
+          delete [] buffer;
+        } // if we allocated the buffer
+      } // if we got mask size
+
+      DeleteDC(hDC);
+      DeleteObject(iconInfo.hbmColor);
+      DeleteObject(iconInfo.hbmMask);
+    } // if we got icon info
+    DestroyIcon(hIcon);
+  } // if we got an hIcon
+
+  // If we didn't make a stream, then fail.
+  if (!*_retval && NS_SUCCEEDED(rv))
+    rv = NS_ERROR_NOT_AVAILABLE;
+#endif
+  return rv;
+}
 
 NS_IMETHODIMP nsIconChannel::GetContentType(nsACString &aContentType) 
 {
   aContentType.AssignLiteral("image/x-icon");
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/modules/libpr0n/decoders/icon/win/nsIconChannel.h
+++ b/modules/libpr0n/decoders/icon/win/nsIconChannel.h
@@ -75,12 +75,20 @@ protected:
   PRInt32          mContentLength;
   nsCOMPtr<nsILoadGroup> mLoadGroup;
   nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
   nsCOMPtr<nsISupports>  mOwner; 
 
   nsCOMPtr<nsIInputStreamPump> mPump;
   nsCOMPtr<nsIStreamListener>  mListener;
 
-  nsresult MakeInputStream(nsIInputStream** _retval);
+  nsresult ExtractIconInfoFromUrl(nsIFile ** aLocalFile, PRUint32 * aDesiredImageSize, nsCString &aContentType, nsCString &aFileExtension);
+  nsresult GetHIconFromFile(HICON *hIcon);
+  nsresult MakeInputStream(nsIInputStream** _retval, PRBool nonBlocking);
+
+  // Functions specific to Vista and above
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
+protected:
+  nsresult GetStockHIcon(nsIMozIconURI *aIconURI, HICON *hIcon);
+#endif
 };
 
 #endif /* nsIconChannel_h___ */