michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/ArrayUtils.h" michael@0: michael@0: #include "nsIconChannel.h" michael@0: #include "nsIIconURI.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsXPIDLString.h" michael@0: #include "nsReadableUtils.h" michael@0: #include "nsMimeTypes.h" michael@0: #include "nsMemory.h" michael@0: #include "nsIStringStream.h" michael@0: #include "nsIURL.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsIFile.h" michael@0: #include "nsIFileURL.h" michael@0: #include "nsIMIMEService.h" michael@0: #include "nsCExternalHandlerService.h" michael@0: #include "nsDirectoryServiceDefs.h" michael@0: michael@0: #ifdef _WIN32_WINNT michael@0: #undef _WIN32_WINNT michael@0: #endif michael@0: #define _WIN32_WINNT 0x0600 michael@0: michael@0: // we need windows.h to read out registry information... michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: using namespace mozilla; michael@0: michael@0: struct ICONFILEHEADER { michael@0: uint16_t ifhReserved; michael@0: uint16_t ifhType; michael@0: uint16_t ifhCount; michael@0: }; michael@0: michael@0: struct ICONENTRY { michael@0: int8_t ieWidth; michael@0: int8_t ieHeight; michael@0: uint8_t ieColors; michael@0: uint8_t ieReserved; michael@0: uint16_t iePlanes; michael@0: uint16_t ieBitCount; michael@0: uint32_t ieSizeImage; michael@0: uint32_t ieFileOffset; michael@0: }; michael@0: michael@0: // Match stock icons with names michael@0: static SHSTOCKICONID GetStockIconIDForName(const nsACString &aStockName) michael@0: { michael@0: // UAC shield icon michael@0: if (aStockName == NS_LITERAL_CSTRING("uac-shield")) michael@0: return SIID_SHIELD; michael@0: michael@0: return SIID_INVALID; michael@0: } michael@0: michael@0: // nsIconChannel methods michael@0: nsIconChannel::nsIconChannel() michael@0: { michael@0: } michael@0: michael@0: nsIconChannel::~nsIconChannel() michael@0: {} michael@0: michael@0: NS_IMPL_ISUPPORTS(nsIconChannel, michael@0: nsIChannel, michael@0: nsIRequest, michael@0: nsIRequestObserver, michael@0: nsIStreamListener) michael@0: michael@0: nsresult nsIconChannel::Init(nsIURI* uri) michael@0: { michael@0: NS_ASSERTION(uri, "no uri"); michael@0: mUrl = uri; michael@0: mOriginalURI = uri; michael@0: nsresult rv; michael@0: mPump = do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv); michael@0: return rv; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIRequest methods: michael@0: michael@0: NS_IMETHODIMP nsIconChannel::GetName(nsACString &result) michael@0: { michael@0: return mUrl->GetSpec(result); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::IsPending(bool *result) michael@0: { michael@0: return mPump->IsPending(result); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::GetStatus(nsresult *status) michael@0: { michael@0: return mPump->GetStatus(status); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::Cancel(nsresult status) michael@0: { michael@0: return mPump->Cancel(status); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::Suspend(void) michael@0: { michael@0: return mPump->Suspend(); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::Resume(void) michael@0: { michael@0: return mPump->Resume(); michael@0: } michael@0: NS_IMETHODIMP nsIconChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup) michael@0: { michael@0: *aLoadGroup = mLoadGroup; michael@0: NS_IF_ADDREF(*aLoadGroup); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) michael@0: { michael@0: mLoadGroup = aLoadGroup; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::GetLoadFlags(uint32_t *aLoadAttributes) michael@0: { michael@0: return mPump->GetLoadFlags(aLoadAttributes); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::SetLoadFlags(uint32_t aLoadAttributes) michael@0: { michael@0: return mPump->SetLoadFlags(aLoadAttributes); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // nsIChannel methods: michael@0: michael@0: NS_IMETHODIMP nsIconChannel::GetOriginalURI(nsIURI* *aURI) michael@0: { michael@0: *aURI = mOriginalURI; michael@0: NS_ADDREF(*aURI); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::SetOriginalURI(nsIURI* aURI) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aURI); michael@0: mOriginalURI = aURI; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::GetURI(nsIURI* *aURI) michael@0: { michael@0: *aURI = mUrl; michael@0: NS_IF_ADDREF(*aURI); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsIconChannel::Open(nsIInputStream **_retval) michael@0: { michael@0: return MakeInputStream(_retval, false); michael@0: } michael@0: michael@0: nsresult nsIconChannel::ExtractIconInfoFromUrl(nsIFile ** aLocalFile, uint32_t * aDesiredImageSize, nsCString &aContentType, nsCString &aFileExtension) michael@0: { michael@0: nsresult rv = NS_OK; michael@0: nsCOMPtr iconURI (do_QueryInterface(mUrl, &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: iconURI->GetImageSize(aDesiredImageSize); michael@0: iconURI->GetContentType(aContentType); michael@0: iconURI->GetFileExtension(aFileExtension); michael@0: michael@0: nsCOMPtr url; michael@0: rv = iconURI->GetIconURL(getter_AddRefs(url)); michael@0: if (NS_FAILED(rv) || !url) return NS_OK; michael@0: michael@0: nsCOMPtr fileURL = do_QueryInterface(url, &rv); michael@0: if (NS_FAILED(rv) || !fileURL) return NS_OK; michael@0: michael@0: nsCOMPtr file; michael@0: rv = fileURL->GetFile(getter_AddRefs(file)); michael@0: if (NS_FAILED(rv) || !file) return NS_OK; michael@0: michael@0: return file->Clone(aLocalFile); michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt) michael@0: { michael@0: nsCOMPtr inStream; michael@0: nsresult rv = MakeInputStream(getter_AddRefs(inStream), true); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: // Init our streampump michael@0: rv = mPump->Init(inStream, int64_t(-1), int64_t(-1), 0, 0, false); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: rv = mPump->AsyncRead(this, ctxt); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: // Store our real listener michael@0: mListener = aListener; michael@0: // Add ourself to the load group, if available michael@0: if (mLoadGroup) michael@0: mLoadGroup->AddRequest(this, nullptr); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: static DWORD GetSpecialFolderIcon(nsIFile* aFile, int aFolder, SHFILEINFOW* aSFI, UINT aInfoFlags) michael@0: { michael@0: DWORD shellResult = 0; michael@0: michael@0: if (!aFile) michael@0: return shellResult; michael@0: michael@0: wchar_t fileNativePath[MAX_PATH]; michael@0: nsAutoString fileNativePathStr; michael@0: aFile->GetPath(fileNativePathStr); michael@0: ::GetShortPathNameW(fileNativePathStr.get(), fileNativePath, ArrayLength(fileNativePath)); michael@0: michael@0: LPITEMIDLIST idList; michael@0: HRESULT hr = ::SHGetSpecialFolderLocation(nullptr, aFolder, &idList); michael@0: if (SUCCEEDED(hr)) { michael@0: wchar_t specialNativePath[MAX_PATH]; michael@0: ::SHGetPathFromIDListW(idList, specialNativePath); michael@0: ::GetShortPathNameW(specialNativePath, specialNativePath, ArrayLength(specialNativePath)); michael@0: michael@0: if (!wcsicmp(fileNativePath, specialNativePath)) { michael@0: aInfoFlags |= (SHGFI_PIDL | SHGFI_SYSICONINDEX); michael@0: shellResult = ::SHGetFileInfoW((LPCWSTR)(LPCITEMIDLIST)idList, 0, aSFI, michael@0: sizeof(*aSFI), aInfoFlags); michael@0: } michael@0: } michael@0: CoTaskMemFree(idList); michael@0: return shellResult; michael@0: } michael@0: michael@0: static UINT GetSizeInfoFlag(uint32_t aDesiredImageSize) michael@0: { michael@0: UINT infoFlag; michael@0: if (aDesiredImageSize > 16) michael@0: infoFlag = SHGFI_SHELLICONSIZE; michael@0: else michael@0: infoFlag = SHGFI_SMALLICON; michael@0: michael@0: return infoFlag; michael@0: } michael@0: michael@0: nsresult nsIconChannel::GetHIconFromFile(HICON *hIcon) michael@0: { michael@0: nsXPIDLCString contentType; michael@0: nsCString fileExt; michael@0: nsCOMPtr localFile; // file we want an icon for michael@0: uint32_t desiredImageSize; michael@0: nsresult rv = ExtractIconInfoFromUrl(getter_AddRefs(localFile), &desiredImageSize, contentType, fileExt); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // if the file exists, we are going to use it's real attributes...otherwise we only want to use it for it's extension... michael@0: SHFILEINFOW sfi; michael@0: UINT infoFlags = SHGFI_ICON; michael@0: michael@0: bool fileExists = false; michael@0: michael@0: nsAutoString filePath; michael@0: CopyASCIItoUTF16(fileExt, filePath); michael@0: if (localFile) michael@0: { michael@0: rv = localFile->Normalize(); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: localFile->GetPath(filePath); michael@0: if (filePath.Length() < 2 || filePath[1] != ':') michael@0: return NS_ERROR_MALFORMED_URI; // UNC michael@0: michael@0: if (filePath.Last() == ':') michael@0: filePath.Append('\\'); michael@0: else { michael@0: localFile->Exists(&fileExists); michael@0: if (!fileExists) michael@0: localFile->GetLeafName(filePath); michael@0: } michael@0: } michael@0: michael@0: if (!fileExists) michael@0: infoFlags |= SHGFI_USEFILEATTRIBUTES; michael@0: michael@0: infoFlags |= GetSizeInfoFlag(desiredImageSize); michael@0: michael@0: // if we have a content type... then use it! but for existing files, we want michael@0: // to show their real icon. michael@0: if (!fileExists && !contentType.IsEmpty()) michael@0: { michael@0: nsCOMPtr mimeService (do_GetService(NS_MIMESERVICE_CONTRACTID, &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsAutoCString defFileExt; michael@0: mimeService->GetPrimaryExtension(contentType, fileExt, defFileExt); michael@0: // If the mime service does not know about this mime type, we show michael@0: // the generic icon. michael@0: // In any case, we need to insert a '.' before the extension. michael@0: filePath = NS_LITERAL_STRING(".") + NS_ConvertUTF8toUTF16(defFileExt); michael@0: } michael@0: michael@0: // Is this the "Desktop" folder? michael@0: DWORD shellResult = GetSpecialFolderIcon(localFile, CSIDL_DESKTOP, &sfi, infoFlags); michael@0: if (!shellResult) { michael@0: // Is this the "My Documents" folder? michael@0: shellResult = GetSpecialFolderIcon(localFile, CSIDL_PERSONAL, &sfi, infoFlags); michael@0: } michael@0: michael@0: // There are other "Special Folders" and Namespace entities that we are not michael@0: // fetching icons for, see: michael@0: // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/enums/csidl.asp michael@0: // If we ever need to get them, code to do so would be inserted here. michael@0: michael@0: // Not a special folder, or something else failed above. michael@0: if (!shellResult) michael@0: shellResult = ::SHGetFileInfoW(filePath.get(), michael@0: FILE_ATTRIBUTE_ARCHIVE, &sfi, sizeof(sfi), infoFlags); michael@0: michael@0: if (shellResult && sfi.hIcon) michael@0: *hIcon = sfi.hIcon; michael@0: else michael@0: rv = NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: nsresult nsIconChannel::GetStockHIcon(nsIMozIconURI *aIconURI, HICON *hIcon) michael@0: { michael@0: nsresult rv = NS_OK; michael@0: michael@0: // We can only do this on Vista or above michael@0: HMODULE hShellDLL = ::LoadLibraryW(L"shell32.dll"); michael@0: decltype(SHGetStockIconInfo)* pSHGetStockIconInfo = michael@0: (decltype(SHGetStockIconInfo)*) ::GetProcAddress(hShellDLL, "SHGetStockIconInfo"); michael@0: michael@0: if (pSHGetStockIconInfo) michael@0: { michael@0: uint32_t desiredImageSize; michael@0: aIconURI->GetImageSize(&desiredImageSize); michael@0: nsAutoCString stockIcon; michael@0: aIconURI->GetStockIcon(stockIcon); michael@0: michael@0: SHSTOCKICONID stockIconID = GetStockIconIDForName(stockIcon); michael@0: if (stockIconID == SIID_INVALID) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: UINT infoFlags = SHGSI_ICON; michael@0: infoFlags |= GetSizeInfoFlag(desiredImageSize); michael@0: michael@0: SHSTOCKICONINFO sii = {0}; michael@0: sii.cbSize = sizeof(sii); michael@0: HRESULT hr = pSHGetStockIconInfo(stockIconID, infoFlags, &sii); michael@0: michael@0: if (SUCCEEDED(hr)) michael@0: *hIcon = sii.hIcon; michael@0: else michael@0: rv = NS_ERROR_FAILURE; michael@0: } michael@0: else michael@0: { michael@0: rv = NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: if (hShellDLL) michael@0: ::FreeLibrary(hShellDLL); michael@0: michael@0: return rv; michael@0: } michael@0: michael@0: // Given a BITMAPINFOHEADER, returns the size of the color table. michael@0: static int GetColorTableSize(BITMAPINFOHEADER* aHeader) michael@0: { michael@0: int colorTableSize = -1; michael@0: michael@0: // http://msdn.microsoft.com/en-us/library/dd183376%28v=VS.85%29.aspx michael@0: switch (aHeader->biBitCount) { michael@0: case 0: michael@0: colorTableSize = 0; michael@0: break; michael@0: case 1: michael@0: colorTableSize = 2 * sizeof(RGBQUAD); michael@0: break; michael@0: case 4: michael@0: case 8: michael@0: { michael@0: // The maximum possible size for the color table is 2**bpp, so check for michael@0: // that and fail if we're not in those bounds michael@0: unsigned int maxEntries = 1 << (aHeader->biBitCount); michael@0: if (aHeader->biClrUsed > 0 && aHeader->biClrUsed <= maxEntries) michael@0: colorTableSize = aHeader->biClrUsed * sizeof(RGBQUAD); michael@0: else if (aHeader->biClrUsed == 0) michael@0: colorTableSize = maxEntries * sizeof(RGBQUAD); michael@0: break; michael@0: } michael@0: case 16: michael@0: case 32: michael@0: // If we have BI_BITFIELDS compression, we would normally need 3 DWORDS for michael@0: // the bitfields mask which would be stored in the color table; However, michael@0: // we instead force the bitmap to request data of type BI_RGB so the color michael@0: // table should be of size 0. michael@0: // Setting aHeader->biCompression = BI_RGB forces the later call to michael@0: // GetDIBits to return to us BI_RGB data. michael@0: if (aHeader->biCompression == BI_BITFIELDS) { michael@0: aHeader->biCompression = BI_RGB; michael@0: } michael@0: colorTableSize = 0; michael@0: break; michael@0: case 24: michael@0: colorTableSize = 0; michael@0: break; michael@0: } michael@0: michael@0: if (colorTableSize < 0) michael@0: NS_WARNING("Unable to figure out the color table size for this bitmap"); michael@0: michael@0: return colorTableSize; michael@0: } michael@0: michael@0: // Given a header and a size, creates a freshly allocated BITMAPINFO structure. michael@0: // It is the caller's responsibility to null-check and delete the structure. michael@0: static BITMAPINFO* CreateBitmapInfo(BITMAPINFOHEADER* aHeader, michael@0: size_t aColorTableSize) michael@0: { michael@0: BITMAPINFO* bmi = (BITMAPINFO*) ::operator new(sizeof(BITMAPINFOHEADER) + michael@0: aColorTableSize, michael@0: mozilla::fallible_t()); michael@0: if (bmi) { michael@0: memcpy(bmi, aHeader, sizeof(BITMAPINFOHEADER)); michael@0: memset(bmi->bmiColors, 0, aColorTableSize); michael@0: } michael@0: return bmi; michael@0: } michael@0: michael@0: nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool nonBlocking) michael@0: { michael@0: // Check whether the icon requested's a file icon or a stock icon michael@0: nsresult rv = NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: // GetDIBits does not exist on windows mobile. michael@0: HICON hIcon = nullptr; michael@0: michael@0: nsCOMPtr iconURI(do_QueryInterface(mUrl, &rv)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsAutoCString stockIcon; michael@0: iconURI->GetStockIcon(stockIcon); michael@0: if (!stockIcon.IsEmpty()) michael@0: rv = GetStockHIcon(iconURI, &hIcon); michael@0: else michael@0: rv = GetHIconFromFile(&hIcon); michael@0: michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: if (hIcon) michael@0: { michael@0: // we got a handle to an icon. Now we want to get a bitmap for the icon using GetIconInfo.... michael@0: ICONINFO iconInfo; michael@0: if (GetIconInfo(hIcon, &iconInfo)) michael@0: { michael@0: // we got the bitmaps, first find out their size michael@0: HDC hDC = CreateCompatibleDC(nullptr); // get a device context for the screen. michael@0: BITMAPINFOHEADER maskHeader = {sizeof(BITMAPINFOHEADER)}; michael@0: BITMAPINFOHEADER colorHeader = {sizeof(BITMAPINFOHEADER)}; michael@0: int colorTableSize, maskTableSize; michael@0: if (GetDIBits(hDC, iconInfo.hbmMask, 0, 0, nullptr, (BITMAPINFO*)&maskHeader, DIB_RGB_COLORS) && michael@0: GetDIBits(hDC, iconInfo.hbmColor, 0, 0, nullptr, (BITMAPINFO*)&colorHeader, DIB_RGB_COLORS) && michael@0: maskHeader.biHeight == colorHeader.biHeight && michael@0: maskHeader.biWidth == colorHeader.biWidth && michael@0: colorHeader.biBitCount > 8 && michael@0: colorHeader.biSizeImage > 0 && michael@0: colorHeader.biWidth >= 0 && colorHeader.biWidth <= 255 && michael@0: colorHeader.biHeight >= 0 && colorHeader.biHeight <= 255 && michael@0: maskHeader.biSizeImage > 0 && michael@0: (colorTableSize = GetColorTableSize(&colorHeader)) >= 0 && michael@0: (maskTableSize = GetColorTableSize(&maskHeader)) >= 0) { michael@0: uint32_t iconSize = sizeof(ICONFILEHEADER) + michael@0: sizeof(ICONENTRY) + michael@0: sizeof(BITMAPINFOHEADER) + michael@0: colorHeader.biSizeImage + michael@0: maskHeader.biSizeImage; michael@0: michael@0: char *buffer = new char[iconSize]; michael@0: if (!buffer) michael@0: rv = NS_ERROR_OUT_OF_MEMORY; michael@0: else { michael@0: char *whereTo = buffer; michael@0: int howMuch; michael@0: michael@0: // the data starts with an icon file header michael@0: ICONFILEHEADER iconHeader; michael@0: iconHeader.ifhReserved = 0; michael@0: iconHeader.ifhType = 1; michael@0: iconHeader.ifhCount = 1; michael@0: howMuch = sizeof(ICONFILEHEADER); michael@0: memcpy(whereTo, &iconHeader, howMuch); michael@0: whereTo += howMuch; michael@0: michael@0: // followed by the single icon entry michael@0: ICONENTRY iconEntry; michael@0: iconEntry.ieWidth = static_cast(colorHeader.biWidth); michael@0: iconEntry.ieHeight = static_cast(colorHeader.biHeight); michael@0: iconEntry.ieColors = 0; michael@0: iconEntry.ieReserved = 0; michael@0: iconEntry.iePlanes = 1; michael@0: iconEntry.ieBitCount = colorHeader.biBitCount; michael@0: iconEntry.ieSizeImage = sizeof(BITMAPINFOHEADER) + michael@0: colorHeader.biSizeImage + michael@0: maskHeader.biSizeImage; michael@0: iconEntry.ieFileOffset = sizeof(ICONFILEHEADER) + sizeof(ICONENTRY); michael@0: howMuch = sizeof(ICONENTRY); michael@0: memcpy(whereTo, &iconEntry, howMuch); michael@0: whereTo += howMuch; michael@0: michael@0: // followed by the bitmap info header michael@0: // (doubling the height because icons have two bitmaps) michael@0: colorHeader.biHeight *= 2; michael@0: colorHeader.biSizeImage += maskHeader.biSizeImage; michael@0: howMuch = sizeof(BITMAPINFOHEADER); michael@0: memcpy(whereTo, &colorHeader, howMuch); michael@0: whereTo += howMuch; michael@0: colorHeader.biHeight /= 2; michael@0: colorHeader.biSizeImage -= maskHeader.biSizeImage; michael@0: michael@0: // followed by the XOR bitmap data (colorHeader) michael@0: // (you'd expect the color table to come here, but it apparently doesn't) michael@0: BITMAPINFO* colorInfo = CreateBitmapInfo(&colorHeader, colorTableSize); michael@0: if (colorInfo && GetDIBits(hDC, iconInfo.hbmColor, 0, michael@0: colorHeader.biHeight, whereTo, colorInfo, michael@0: DIB_RGB_COLORS)) { michael@0: whereTo += colorHeader.biSizeImage; michael@0: michael@0: // and finally the AND bitmap data (maskHeader) michael@0: BITMAPINFO* maskInfo = CreateBitmapInfo(&maskHeader, maskTableSize); michael@0: if (maskInfo && GetDIBits(hDC, iconInfo.hbmMask, 0, michael@0: maskHeader.biHeight, whereTo, maskInfo, michael@0: DIB_RGB_COLORS)) { michael@0: // Now, create a pipe and stuff our data into it michael@0: nsCOMPtr inStream; michael@0: nsCOMPtr outStream; michael@0: rv = NS_NewPipe(getter_AddRefs(inStream), getter_AddRefs(outStream), michael@0: iconSize, iconSize, nonBlocking); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: uint32_t written; michael@0: rv = outStream->Write(buffer, iconSize, &written); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: NS_ADDREF(*_retval = inStream); michael@0: } michael@0: } michael@0: michael@0: } // if we got bitmap bits michael@0: delete maskInfo; michael@0: } // if we got mask bits michael@0: delete colorInfo; michael@0: delete [] buffer; michael@0: } // if we allocated the buffer michael@0: } // if we got mask size michael@0: michael@0: DeleteDC(hDC); michael@0: DeleteObject(iconInfo.hbmColor); michael@0: DeleteObject(iconInfo.hbmMask); michael@0: } // if we got icon info michael@0: DestroyIcon(hIcon); michael@0: } // if we got an hIcon michael@0: michael@0: // If we didn't make a stream, then fail. michael@0: if (!*_retval && NS_SUCCEEDED(rv)) michael@0: rv = NS_ERROR_NOT_AVAILABLE; michael@0: return rv; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::GetContentType(nsACString &aContentType) michael@0: { michael@0: aContentType.AssignLiteral(IMAGE_ICO); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsIconChannel::SetContentType(const nsACString &aContentType) michael@0: { michael@0: // It doesn't make sense to set the content-type on this type michael@0: // of channel... michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::GetContentCharset(nsACString &aContentCharset) michael@0: { michael@0: aContentCharset.Truncate(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsIconChannel::SetContentCharset(const nsACString &aContentCharset) michael@0: { michael@0: // It doesn't make sense to set the content-charset on this type michael@0: // of channel... michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsIconChannel::GetContentDisposition(uint32_t *aContentDisposition) michael@0: { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsIconChannel::SetContentDisposition(uint32_t aContentDisposition) michael@0: { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsIconChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename) michael@0: { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsIconChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename) michael@0: { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsIconChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader) michael@0: { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::GetContentLength(int64_t *aContentLength) michael@0: { michael@0: *aContentLength = mContentLength; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::SetContentLength(int64_t aContentLength) michael@0: { michael@0: NS_NOTREACHED("nsIconChannel::SetContentLength"); michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::GetOwner(nsISupports* *aOwner) michael@0: { michael@0: *aOwner = mOwner.get(); michael@0: NS_IF_ADDREF(*aOwner); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::SetOwner(nsISupports* aOwner) michael@0: { michael@0: mOwner = aOwner; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks) michael@0: { michael@0: *aNotificationCallbacks = mCallbacks.get(); michael@0: NS_IF_ADDREF(*aNotificationCallbacks); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks) michael@0: { michael@0: mCallbacks = aNotificationCallbacks; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::GetSecurityInfo(nsISupports * *aSecurityInfo) michael@0: { michael@0: *aSecurityInfo = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // nsIRequestObserver methods michael@0: NS_IMETHODIMP nsIconChannel::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) michael@0: { michael@0: if (mListener) michael@0: return mListener->OnStartRequest(this, aContext); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsIconChannel::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatus) michael@0: { michael@0: if (mListener) { michael@0: mListener->OnStopRequest(this, aContext, aStatus); michael@0: mListener = nullptr; michael@0: } michael@0: michael@0: // Remove from load group michael@0: if (mLoadGroup) michael@0: mLoadGroup->RemoveRequest(this, nullptr, aStatus); michael@0: michael@0: // Drop notification callbacks to prevent cycles. michael@0: mCallbacks = nullptr; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // nsIStreamListener methods michael@0: NS_IMETHODIMP nsIconChannel::OnDataAvailable(nsIRequest* aRequest, michael@0: nsISupports* aContext, michael@0: nsIInputStream* aStream, michael@0: uint64_t aOffset, michael@0: uint32_t aCount) michael@0: { michael@0: if (mListener) michael@0: return mListener->OnDataAvailable(this, aContext, aStream, aOffset, aCount); michael@0: return NS_OK; michael@0: }