1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/image/decoders/icon/win/nsIconChannel.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,725 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "mozilla/ArrayUtils.h" 1.11 + 1.12 +#include "nsIconChannel.h" 1.13 +#include "nsIIconURI.h" 1.14 +#include "nsIServiceManager.h" 1.15 +#include "nsIInterfaceRequestor.h" 1.16 +#include "nsIInterfaceRequestorUtils.h" 1.17 +#include "nsXPIDLString.h" 1.18 +#include "nsReadableUtils.h" 1.19 +#include "nsMimeTypes.h" 1.20 +#include "nsMemory.h" 1.21 +#include "nsIStringStream.h" 1.22 +#include "nsIURL.h" 1.23 +#include "nsNetUtil.h" 1.24 +#include "nsIFile.h" 1.25 +#include "nsIFileURL.h" 1.26 +#include "nsIMIMEService.h" 1.27 +#include "nsCExternalHandlerService.h" 1.28 +#include "nsDirectoryServiceDefs.h" 1.29 + 1.30 +#ifdef _WIN32_WINNT 1.31 +#undef _WIN32_WINNT 1.32 +#endif 1.33 +#define _WIN32_WINNT 0x0600 1.34 + 1.35 +// we need windows.h to read out registry information... 1.36 +#include <windows.h> 1.37 +#include <shellapi.h> 1.38 +#include <shlobj.h> 1.39 +#include <objbase.h> 1.40 +#include <wchar.h> 1.41 + 1.42 +using namespace mozilla; 1.43 + 1.44 +struct ICONFILEHEADER { 1.45 + uint16_t ifhReserved; 1.46 + uint16_t ifhType; 1.47 + uint16_t ifhCount; 1.48 +}; 1.49 + 1.50 +struct ICONENTRY { 1.51 + int8_t ieWidth; 1.52 + int8_t ieHeight; 1.53 + uint8_t ieColors; 1.54 + uint8_t ieReserved; 1.55 + uint16_t iePlanes; 1.56 + uint16_t ieBitCount; 1.57 + uint32_t ieSizeImage; 1.58 + uint32_t ieFileOffset; 1.59 +}; 1.60 + 1.61 +// Match stock icons with names 1.62 +static SHSTOCKICONID GetStockIconIDForName(const nsACString &aStockName) 1.63 +{ 1.64 + // UAC shield icon 1.65 + if (aStockName == NS_LITERAL_CSTRING("uac-shield")) 1.66 + return SIID_SHIELD; 1.67 + 1.68 + return SIID_INVALID; 1.69 +} 1.70 + 1.71 +// nsIconChannel methods 1.72 +nsIconChannel::nsIconChannel() 1.73 +{ 1.74 +} 1.75 + 1.76 +nsIconChannel::~nsIconChannel() 1.77 +{} 1.78 + 1.79 +NS_IMPL_ISUPPORTS(nsIconChannel, 1.80 + nsIChannel, 1.81 + nsIRequest, 1.82 + nsIRequestObserver, 1.83 + nsIStreamListener) 1.84 + 1.85 +nsresult nsIconChannel::Init(nsIURI* uri) 1.86 +{ 1.87 + NS_ASSERTION(uri, "no uri"); 1.88 + mUrl = uri; 1.89 + mOriginalURI = uri; 1.90 + nsresult rv; 1.91 + mPump = do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv); 1.92 + return rv; 1.93 +} 1.94 + 1.95 +//////////////////////////////////////////////////////////////////////////////// 1.96 +// nsIRequest methods: 1.97 + 1.98 +NS_IMETHODIMP nsIconChannel::GetName(nsACString &result) 1.99 +{ 1.100 + return mUrl->GetSpec(result); 1.101 +} 1.102 + 1.103 +NS_IMETHODIMP nsIconChannel::IsPending(bool *result) 1.104 +{ 1.105 + return mPump->IsPending(result); 1.106 +} 1.107 + 1.108 +NS_IMETHODIMP nsIconChannel::GetStatus(nsresult *status) 1.109 +{ 1.110 + return mPump->GetStatus(status); 1.111 +} 1.112 + 1.113 +NS_IMETHODIMP nsIconChannel::Cancel(nsresult status) 1.114 +{ 1.115 + return mPump->Cancel(status); 1.116 +} 1.117 + 1.118 +NS_IMETHODIMP nsIconChannel::Suspend(void) 1.119 +{ 1.120 + return mPump->Suspend(); 1.121 +} 1.122 + 1.123 +NS_IMETHODIMP nsIconChannel::Resume(void) 1.124 +{ 1.125 + return mPump->Resume(); 1.126 +} 1.127 +NS_IMETHODIMP nsIconChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup) 1.128 +{ 1.129 + *aLoadGroup = mLoadGroup; 1.130 + NS_IF_ADDREF(*aLoadGroup); 1.131 + return NS_OK; 1.132 +} 1.133 + 1.134 +NS_IMETHODIMP nsIconChannel::SetLoadGroup(nsILoadGroup* aLoadGroup) 1.135 +{ 1.136 + mLoadGroup = aLoadGroup; 1.137 + return NS_OK; 1.138 +} 1.139 + 1.140 +NS_IMETHODIMP nsIconChannel::GetLoadFlags(uint32_t *aLoadAttributes) 1.141 +{ 1.142 + return mPump->GetLoadFlags(aLoadAttributes); 1.143 +} 1.144 + 1.145 +NS_IMETHODIMP nsIconChannel::SetLoadFlags(uint32_t aLoadAttributes) 1.146 +{ 1.147 + return mPump->SetLoadFlags(aLoadAttributes); 1.148 +} 1.149 + 1.150 +//////////////////////////////////////////////////////////////////////////////// 1.151 +// nsIChannel methods: 1.152 + 1.153 +NS_IMETHODIMP nsIconChannel::GetOriginalURI(nsIURI* *aURI) 1.154 +{ 1.155 + *aURI = mOriginalURI; 1.156 + NS_ADDREF(*aURI); 1.157 + return NS_OK; 1.158 +} 1.159 + 1.160 +NS_IMETHODIMP nsIconChannel::SetOriginalURI(nsIURI* aURI) 1.161 +{ 1.162 + NS_ENSURE_ARG_POINTER(aURI); 1.163 + mOriginalURI = aURI; 1.164 + return NS_OK; 1.165 +} 1.166 + 1.167 +NS_IMETHODIMP nsIconChannel::GetURI(nsIURI* *aURI) 1.168 +{ 1.169 + *aURI = mUrl; 1.170 + NS_IF_ADDREF(*aURI); 1.171 + return NS_OK; 1.172 +} 1.173 + 1.174 +NS_IMETHODIMP 1.175 +nsIconChannel::Open(nsIInputStream **_retval) 1.176 +{ 1.177 + return MakeInputStream(_retval, false); 1.178 +} 1.179 + 1.180 +nsresult nsIconChannel::ExtractIconInfoFromUrl(nsIFile ** aLocalFile, uint32_t * aDesiredImageSize, nsCString &aContentType, nsCString &aFileExtension) 1.181 +{ 1.182 + nsresult rv = NS_OK; 1.183 + nsCOMPtr<nsIMozIconURI> iconURI (do_QueryInterface(mUrl, &rv)); 1.184 + NS_ENSURE_SUCCESS(rv, rv); 1.185 + 1.186 + iconURI->GetImageSize(aDesiredImageSize); 1.187 + iconURI->GetContentType(aContentType); 1.188 + iconURI->GetFileExtension(aFileExtension); 1.189 + 1.190 + nsCOMPtr<nsIURL> url; 1.191 + rv = iconURI->GetIconURL(getter_AddRefs(url)); 1.192 + if (NS_FAILED(rv) || !url) return NS_OK; 1.193 + 1.194 + nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(url, &rv); 1.195 + if (NS_FAILED(rv) || !fileURL) return NS_OK; 1.196 + 1.197 + nsCOMPtr<nsIFile> file; 1.198 + rv = fileURL->GetFile(getter_AddRefs(file)); 1.199 + if (NS_FAILED(rv) || !file) return NS_OK; 1.200 + 1.201 + return file->Clone(aLocalFile); 1.202 +} 1.203 + 1.204 +NS_IMETHODIMP nsIconChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt) 1.205 +{ 1.206 + nsCOMPtr<nsIInputStream> inStream; 1.207 + nsresult rv = MakeInputStream(getter_AddRefs(inStream), true); 1.208 + if (NS_FAILED(rv)) 1.209 + return rv; 1.210 + 1.211 + // Init our streampump 1.212 + rv = mPump->Init(inStream, int64_t(-1), int64_t(-1), 0, 0, false); 1.213 + if (NS_FAILED(rv)) 1.214 + return rv; 1.215 + 1.216 + rv = mPump->AsyncRead(this, ctxt); 1.217 + if (NS_SUCCEEDED(rv)) { 1.218 + // Store our real listener 1.219 + mListener = aListener; 1.220 + // Add ourself to the load group, if available 1.221 + if (mLoadGroup) 1.222 + mLoadGroup->AddRequest(this, nullptr); 1.223 + } 1.224 + return rv; 1.225 +} 1.226 + 1.227 +static DWORD GetSpecialFolderIcon(nsIFile* aFile, int aFolder, SHFILEINFOW* aSFI, UINT aInfoFlags) 1.228 +{ 1.229 + DWORD shellResult = 0; 1.230 + 1.231 + if (!aFile) 1.232 + return shellResult; 1.233 + 1.234 + wchar_t fileNativePath[MAX_PATH]; 1.235 + nsAutoString fileNativePathStr; 1.236 + aFile->GetPath(fileNativePathStr); 1.237 + ::GetShortPathNameW(fileNativePathStr.get(), fileNativePath, ArrayLength(fileNativePath)); 1.238 + 1.239 + LPITEMIDLIST idList; 1.240 + HRESULT hr = ::SHGetSpecialFolderLocation(nullptr, aFolder, &idList); 1.241 + if (SUCCEEDED(hr)) { 1.242 + wchar_t specialNativePath[MAX_PATH]; 1.243 + ::SHGetPathFromIDListW(idList, specialNativePath); 1.244 + ::GetShortPathNameW(specialNativePath, specialNativePath, ArrayLength(specialNativePath)); 1.245 + 1.246 + if (!wcsicmp(fileNativePath, specialNativePath)) { 1.247 + aInfoFlags |= (SHGFI_PIDL | SHGFI_SYSICONINDEX); 1.248 + shellResult = ::SHGetFileInfoW((LPCWSTR)(LPCITEMIDLIST)idList, 0, aSFI, 1.249 + sizeof(*aSFI), aInfoFlags); 1.250 + } 1.251 + } 1.252 + CoTaskMemFree(idList); 1.253 + return shellResult; 1.254 +} 1.255 + 1.256 +static UINT GetSizeInfoFlag(uint32_t aDesiredImageSize) 1.257 +{ 1.258 + UINT infoFlag; 1.259 + if (aDesiredImageSize > 16) 1.260 + infoFlag = SHGFI_SHELLICONSIZE; 1.261 + else 1.262 + infoFlag = SHGFI_SMALLICON; 1.263 + 1.264 + return infoFlag; 1.265 +} 1.266 + 1.267 +nsresult nsIconChannel::GetHIconFromFile(HICON *hIcon) 1.268 +{ 1.269 + nsXPIDLCString contentType; 1.270 + nsCString fileExt; 1.271 + nsCOMPtr<nsIFile> localFile; // file we want an icon for 1.272 + uint32_t desiredImageSize; 1.273 + nsresult rv = ExtractIconInfoFromUrl(getter_AddRefs(localFile), &desiredImageSize, contentType, fileExt); 1.274 + NS_ENSURE_SUCCESS(rv, rv); 1.275 + 1.276 + // if the file exists, we are going to use it's real attributes...otherwise we only want to use it for it's extension... 1.277 + SHFILEINFOW sfi; 1.278 + UINT infoFlags = SHGFI_ICON; 1.279 + 1.280 + bool fileExists = false; 1.281 + 1.282 + nsAutoString filePath; 1.283 + CopyASCIItoUTF16(fileExt, filePath); 1.284 + if (localFile) 1.285 + { 1.286 + rv = localFile->Normalize(); 1.287 + NS_ENSURE_SUCCESS(rv, rv); 1.288 + 1.289 + localFile->GetPath(filePath); 1.290 + if (filePath.Length() < 2 || filePath[1] != ':') 1.291 + return NS_ERROR_MALFORMED_URI; // UNC 1.292 + 1.293 + if (filePath.Last() == ':') 1.294 + filePath.Append('\\'); 1.295 + else { 1.296 + localFile->Exists(&fileExists); 1.297 + if (!fileExists) 1.298 + localFile->GetLeafName(filePath); 1.299 + } 1.300 + } 1.301 + 1.302 + if (!fileExists) 1.303 + infoFlags |= SHGFI_USEFILEATTRIBUTES; 1.304 + 1.305 + infoFlags |= GetSizeInfoFlag(desiredImageSize); 1.306 + 1.307 + // if we have a content type... then use it! but for existing files, we want 1.308 + // to show their real icon. 1.309 + if (!fileExists && !contentType.IsEmpty()) 1.310 + { 1.311 + nsCOMPtr<nsIMIMEService> mimeService (do_GetService(NS_MIMESERVICE_CONTRACTID, &rv)); 1.312 + NS_ENSURE_SUCCESS(rv, rv); 1.313 + 1.314 + nsAutoCString defFileExt; 1.315 + mimeService->GetPrimaryExtension(contentType, fileExt, defFileExt); 1.316 + // If the mime service does not know about this mime type, we show 1.317 + // the generic icon. 1.318 + // In any case, we need to insert a '.' before the extension. 1.319 + filePath = NS_LITERAL_STRING(".") + NS_ConvertUTF8toUTF16(defFileExt); 1.320 + } 1.321 + 1.322 + // Is this the "Desktop" folder? 1.323 + DWORD shellResult = GetSpecialFolderIcon(localFile, CSIDL_DESKTOP, &sfi, infoFlags); 1.324 + if (!shellResult) { 1.325 + // Is this the "My Documents" folder? 1.326 + shellResult = GetSpecialFolderIcon(localFile, CSIDL_PERSONAL, &sfi, infoFlags); 1.327 + } 1.328 + 1.329 + // There are other "Special Folders" and Namespace entities that we are not 1.330 + // fetching icons for, see: 1.331 + // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/enums/csidl.asp 1.332 + // If we ever need to get them, code to do so would be inserted here. 1.333 + 1.334 + // Not a special folder, or something else failed above. 1.335 + if (!shellResult) 1.336 + shellResult = ::SHGetFileInfoW(filePath.get(), 1.337 + FILE_ATTRIBUTE_ARCHIVE, &sfi, sizeof(sfi), infoFlags); 1.338 + 1.339 + if (shellResult && sfi.hIcon) 1.340 + *hIcon = sfi.hIcon; 1.341 + else 1.342 + rv = NS_ERROR_NOT_AVAILABLE; 1.343 + 1.344 + return rv; 1.345 +} 1.346 + 1.347 +nsresult nsIconChannel::GetStockHIcon(nsIMozIconURI *aIconURI, HICON *hIcon) 1.348 +{ 1.349 + nsresult rv = NS_OK; 1.350 + 1.351 + // We can only do this on Vista or above 1.352 + HMODULE hShellDLL = ::LoadLibraryW(L"shell32.dll"); 1.353 + decltype(SHGetStockIconInfo)* pSHGetStockIconInfo = 1.354 + (decltype(SHGetStockIconInfo)*) ::GetProcAddress(hShellDLL, "SHGetStockIconInfo"); 1.355 + 1.356 + if (pSHGetStockIconInfo) 1.357 + { 1.358 + uint32_t desiredImageSize; 1.359 + aIconURI->GetImageSize(&desiredImageSize); 1.360 + nsAutoCString stockIcon; 1.361 + aIconURI->GetStockIcon(stockIcon); 1.362 + 1.363 + SHSTOCKICONID stockIconID = GetStockIconIDForName(stockIcon); 1.364 + if (stockIconID == SIID_INVALID) 1.365 + return NS_ERROR_NOT_AVAILABLE; 1.366 + 1.367 + UINT infoFlags = SHGSI_ICON; 1.368 + infoFlags |= GetSizeInfoFlag(desiredImageSize); 1.369 + 1.370 + SHSTOCKICONINFO sii = {0}; 1.371 + sii.cbSize = sizeof(sii); 1.372 + HRESULT hr = pSHGetStockIconInfo(stockIconID, infoFlags, &sii); 1.373 + 1.374 + if (SUCCEEDED(hr)) 1.375 + *hIcon = sii.hIcon; 1.376 + else 1.377 + rv = NS_ERROR_FAILURE; 1.378 + } 1.379 + else 1.380 + { 1.381 + rv = NS_ERROR_NOT_AVAILABLE; 1.382 + } 1.383 + 1.384 + if (hShellDLL) 1.385 + ::FreeLibrary(hShellDLL); 1.386 + 1.387 + return rv; 1.388 +} 1.389 + 1.390 +// Given a BITMAPINFOHEADER, returns the size of the color table. 1.391 +static int GetColorTableSize(BITMAPINFOHEADER* aHeader) 1.392 +{ 1.393 + int colorTableSize = -1; 1.394 + 1.395 + // http://msdn.microsoft.com/en-us/library/dd183376%28v=VS.85%29.aspx 1.396 + switch (aHeader->biBitCount) { 1.397 + case 0: 1.398 + colorTableSize = 0; 1.399 + break; 1.400 + case 1: 1.401 + colorTableSize = 2 * sizeof(RGBQUAD); 1.402 + break; 1.403 + case 4: 1.404 + case 8: 1.405 + { 1.406 + // The maximum possible size for the color table is 2**bpp, so check for 1.407 + // that and fail if we're not in those bounds 1.408 + unsigned int maxEntries = 1 << (aHeader->biBitCount); 1.409 + if (aHeader->biClrUsed > 0 && aHeader->biClrUsed <= maxEntries) 1.410 + colorTableSize = aHeader->biClrUsed * sizeof(RGBQUAD); 1.411 + else if (aHeader->biClrUsed == 0) 1.412 + colorTableSize = maxEntries * sizeof(RGBQUAD); 1.413 + break; 1.414 + } 1.415 + case 16: 1.416 + case 32: 1.417 + // If we have BI_BITFIELDS compression, we would normally need 3 DWORDS for 1.418 + // the bitfields mask which would be stored in the color table; However, 1.419 + // we instead force the bitmap to request data of type BI_RGB so the color 1.420 + // table should be of size 0. 1.421 + // Setting aHeader->biCompression = BI_RGB forces the later call to 1.422 + // GetDIBits to return to us BI_RGB data. 1.423 + if (aHeader->biCompression == BI_BITFIELDS) { 1.424 + aHeader->biCompression = BI_RGB; 1.425 + } 1.426 + colorTableSize = 0; 1.427 + break; 1.428 + case 24: 1.429 + colorTableSize = 0; 1.430 + break; 1.431 + } 1.432 + 1.433 + if (colorTableSize < 0) 1.434 + NS_WARNING("Unable to figure out the color table size for this bitmap"); 1.435 + 1.436 + return colorTableSize; 1.437 +} 1.438 + 1.439 +// Given a header and a size, creates a freshly allocated BITMAPINFO structure. 1.440 +// It is the caller's responsibility to null-check and delete the structure. 1.441 +static BITMAPINFO* CreateBitmapInfo(BITMAPINFOHEADER* aHeader, 1.442 + size_t aColorTableSize) 1.443 +{ 1.444 + BITMAPINFO* bmi = (BITMAPINFO*) ::operator new(sizeof(BITMAPINFOHEADER) + 1.445 + aColorTableSize, 1.446 + mozilla::fallible_t()); 1.447 + if (bmi) { 1.448 + memcpy(bmi, aHeader, sizeof(BITMAPINFOHEADER)); 1.449 + memset(bmi->bmiColors, 0, aColorTableSize); 1.450 + } 1.451 + return bmi; 1.452 +} 1.453 + 1.454 +nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool nonBlocking) 1.455 +{ 1.456 + // Check whether the icon requested's a file icon or a stock icon 1.457 + nsresult rv = NS_ERROR_NOT_AVAILABLE; 1.458 + 1.459 + // GetDIBits does not exist on windows mobile. 1.460 + HICON hIcon = nullptr; 1.461 + 1.462 + nsCOMPtr<nsIMozIconURI> iconURI(do_QueryInterface(mUrl, &rv)); 1.463 + NS_ENSURE_SUCCESS(rv, rv); 1.464 + 1.465 + nsAutoCString stockIcon; 1.466 + iconURI->GetStockIcon(stockIcon); 1.467 + if (!stockIcon.IsEmpty()) 1.468 + rv = GetStockHIcon(iconURI, &hIcon); 1.469 + else 1.470 + rv = GetHIconFromFile(&hIcon); 1.471 + 1.472 + NS_ENSURE_SUCCESS(rv, rv); 1.473 + 1.474 + if (hIcon) 1.475 + { 1.476 + // we got a handle to an icon. Now we want to get a bitmap for the icon using GetIconInfo.... 1.477 + ICONINFO iconInfo; 1.478 + if (GetIconInfo(hIcon, &iconInfo)) 1.479 + { 1.480 + // we got the bitmaps, first find out their size 1.481 + HDC hDC = CreateCompatibleDC(nullptr); // get a device context for the screen. 1.482 + BITMAPINFOHEADER maskHeader = {sizeof(BITMAPINFOHEADER)}; 1.483 + BITMAPINFOHEADER colorHeader = {sizeof(BITMAPINFOHEADER)}; 1.484 + int colorTableSize, maskTableSize; 1.485 + if (GetDIBits(hDC, iconInfo.hbmMask, 0, 0, nullptr, (BITMAPINFO*)&maskHeader, DIB_RGB_COLORS) && 1.486 + GetDIBits(hDC, iconInfo.hbmColor, 0, 0, nullptr, (BITMAPINFO*)&colorHeader, DIB_RGB_COLORS) && 1.487 + maskHeader.biHeight == colorHeader.biHeight && 1.488 + maskHeader.biWidth == colorHeader.biWidth && 1.489 + colorHeader.biBitCount > 8 && 1.490 + colorHeader.biSizeImage > 0 && 1.491 + colorHeader.biWidth >= 0 && colorHeader.biWidth <= 255 && 1.492 + colorHeader.biHeight >= 0 && colorHeader.biHeight <= 255 && 1.493 + maskHeader.biSizeImage > 0 && 1.494 + (colorTableSize = GetColorTableSize(&colorHeader)) >= 0 && 1.495 + (maskTableSize = GetColorTableSize(&maskHeader)) >= 0) { 1.496 + uint32_t iconSize = sizeof(ICONFILEHEADER) + 1.497 + sizeof(ICONENTRY) + 1.498 + sizeof(BITMAPINFOHEADER) + 1.499 + colorHeader.biSizeImage + 1.500 + maskHeader.biSizeImage; 1.501 + 1.502 + char *buffer = new char[iconSize]; 1.503 + if (!buffer) 1.504 + rv = NS_ERROR_OUT_OF_MEMORY; 1.505 + else { 1.506 + char *whereTo = buffer; 1.507 + int howMuch; 1.508 + 1.509 + // the data starts with an icon file header 1.510 + ICONFILEHEADER iconHeader; 1.511 + iconHeader.ifhReserved = 0; 1.512 + iconHeader.ifhType = 1; 1.513 + iconHeader.ifhCount = 1; 1.514 + howMuch = sizeof(ICONFILEHEADER); 1.515 + memcpy(whereTo, &iconHeader, howMuch); 1.516 + whereTo += howMuch; 1.517 + 1.518 + // followed by the single icon entry 1.519 + ICONENTRY iconEntry; 1.520 + iconEntry.ieWidth = static_cast<int8_t>(colorHeader.biWidth); 1.521 + iconEntry.ieHeight = static_cast<int8_t>(colorHeader.biHeight); 1.522 + iconEntry.ieColors = 0; 1.523 + iconEntry.ieReserved = 0; 1.524 + iconEntry.iePlanes = 1; 1.525 + iconEntry.ieBitCount = colorHeader.biBitCount; 1.526 + iconEntry.ieSizeImage = sizeof(BITMAPINFOHEADER) + 1.527 + colorHeader.biSizeImage + 1.528 + maskHeader.biSizeImage; 1.529 + iconEntry.ieFileOffset = sizeof(ICONFILEHEADER) + sizeof(ICONENTRY); 1.530 + howMuch = sizeof(ICONENTRY); 1.531 + memcpy(whereTo, &iconEntry, howMuch); 1.532 + whereTo += howMuch; 1.533 + 1.534 + // followed by the bitmap info header 1.535 + // (doubling the height because icons have two bitmaps) 1.536 + colorHeader.biHeight *= 2; 1.537 + colorHeader.biSizeImage += maskHeader.biSizeImage; 1.538 + howMuch = sizeof(BITMAPINFOHEADER); 1.539 + memcpy(whereTo, &colorHeader, howMuch); 1.540 + whereTo += howMuch; 1.541 + colorHeader.biHeight /= 2; 1.542 + colorHeader.biSizeImage -= maskHeader.biSizeImage; 1.543 + 1.544 + // followed by the XOR bitmap data (colorHeader) 1.545 + // (you'd expect the color table to come here, but it apparently doesn't) 1.546 + BITMAPINFO* colorInfo = CreateBitmapInfo(&colorHeader, colorTableSize); 1.547 + if (colorInfo && GetDIBits(hDC, iconInfo.hbmColor, 0, 1.548 + colorHeader.biHeight, whereTo, colorInfo, 1.549 + DIB_RGB_COLORS)) { 1.550 + whereTo += colorHeader.biSizeImage; 1.551 + 1.552 + // and finally the AND bitmap data (maskHeader) 1.553 + BITMAPINFO* maskInfo = CreateBitmapInfo(&maskHeader, maskTableSize); 1.554 + if (maskInfo && GetDIBits(hDC, iconInfo.hbmMask, 0, 1.555 + maskHeader.biHeight, whereTo, maskInfo, 1.556 + DIB_RGB_COLORS)) { 1.557 + // Now, create a pipe and stuff our data into it 1.558 + nsCOMPtr<nsIInputStream> inStream; 1.559 + nsCOMPtr<nsIOutputStream> outStream; 1.560 + rv = NS_NewPipe(getter_AddRefs(inStream), getter_AddRefs(outStream), 1.561 + iconSize, iconSize, nonBlocking); 1.562 + if (NS_SUCCEEDED(rv)) { 1.563 + uint32_t written; 1.564 + rv = outStream->Write(buffer, iconSize, &written); 1.565 + if (NS_SUCCEEDED(rv)) { 1.566 + NS_ADDREF(*_retval = inStream); 1.567 + } 1.568 + } 1.569 + 1.570 + } // if we got bitmap bits 1.571 + delete maskInfo; 1.572 + } // if we got mask bits 1.573 + delete colorInfo; 1.574 + delete [] buffer; 1.575 + } // if we allocated the buffer 1.576 + } // if we got mask size 1.577 + 1.578 + DeleteDC(hDC); 1.579 + DeleteObject(iconInfo.hbmColor); 1.580 + DeleteObject(iconInfo.hbmMask); 1.581 + } // if we got icon info 1.582 + DestroyIcon(hIcon); 1.583 + } // if we got an hIcon 1.584 + 1.585 + // If we didn't make a stream, then fail. 1.586 + if (!*_retval && NS_SUCCEEDED(rv)) 1.587 + rv = NS_ERROR_NOT_AVAILABLE; 1.588 + return rv; 1.589 +} 1.590 + 1.591 +NS_IMETHODIMP nsIconChannel::GetContentType(nsACString &aContentType) 1.592 +{ 1.593 + aContentType.AssignLiteral(IMAGE_ICO); 1.594 + return NS_OK; 1.595 +} 1.596 + 1.597 +NS_IMETHODIMP 1.598 +nsIconChannel::SetContentType(const nsACString &aContentType) 1.599 +{ 1.600 + // It doesn't make sense to set the content-type on this type 1.601 + // of channel... 1.602 + return NS_ERROR_FAILURE; 1.603 +} 1.604 + 1.605 +NS_IMETHODIMP nsIconChannel::GetContentCharset(nsACString &aContentCharset) 1.606 +{ 1.607 + aContentCharset.Truncate(); 1.608 + return NS_OK; 1.609 +} 1.610 + 1.611 +NS_IMETHODIMP 1.612 +nsIconChannel::SetContentCharset(const nsACString &aContentCharset) 1.613 +{ 1.614 + // It doesn't make sense to set the content-charset on this type 1.615 + // of channel... 1.616 + return NS_ERROR_FAILURE; 1.617 +} 1.618 + 1.619 +NS_IMETHODIMP 1.620 +nsIconChannel::GetContentDisposition(uint32_t *aContentDisposition) 1.621 +{ 1.622 + return NS_ERROR_NOT_AVAILABLE; 1.623 +} 1.624 + 1.625 +NS_IMETHODIMP 1.626 +nsIconChannel::SetContentDisposition(uint32_t aContentDisposition) 1.627 +{ 1.628 + return NS_ERROR_NOT_AVAILABLE; 1.629 +} 1.630 + 1.631 +NS_IMETHODIMP 1.632 +nsIconChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename) 1.633 +{ 1.634 + return NS_ERROR_NOT_AVAILABLE; 1.635 +} 1.636 + 1.637 +NS_IMETHODIMP 1.638 +nsIconChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename) 1.639 +{ 1.640 + return NS_ERROR_NOT_AVAILABLE; 1.641 +} 1.642 + 1.643 +NS_IMETHODIMP 1.644 +nsIconChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader) 1.645 +{ 1.646 + return NS_ERROR_NOT_AVAILABLE; 1.647 +} 1.648 + 1.649 +NS_IMETHODIMP nsIconChannel::GetContentLength(int64_t *aContentLength) 1.650 +{ 1.651 + *aContentLength = mContentLength; 1.652 + return NS_OK; 1.653 +} 1.654 + 1.655 +NS_IMETHODIMP nsIconChannel::SetContentLength(int64_t aContentLength) 1.656 +{ 1.657 + NS_NOTREACHED("nsIconChannel::SetContentLength"); 1.658 + return NS_ERROR_NOT_IMPLEMENTED; 1.659 +} 1.660 + 1.661 +NS_IMETHODIMP nsIconChannel::GetOwner(nsISupports* *aOwner) 1.662 +{ 1.663 + *aOwner = mOwner.get(); 1.664 + NS_IF_ADDREF(*aOwner); 1.665 + return NS_OK; 1.666 +} 1.667 + 1.668 +NS_IMETHODIMP nsIconChannel::SetOwner(nsISupports* aOwner) 1.669 +{ 1.670 + mOwner = aOwner; 1.671 + return NS_OK; 1.672 +} 1.673 + 1.674 +NS_IMETHODIMP nsIconChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks) 1.675 +{ 1.676 + *aNotificationCallbacks = mCallbacks.get(); 1.677 + NS_IF_ADDREF(*aNotificationCallbacks); 1.678 + return NS_OK; 1.679 +} 1.680 + 1.681 +NS_IMETHODIMP nsIconChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks) 1.682 +{ 1.683 + mCallbacks = aNotificationCallbacks; 1.684 + return NS_OK; 1.685 +} 1.686 + 1.687 +NS_IMETHODIMP nsIconChannel::GetSecurityInfo(nsISupports * *aSecurityInfo) 1.688 +{ 1.689 + *aSecurityInfo = nullptr; 1.690 + return NS_OK; 1.691 +} 1.692 + 1.693 +// nsIRequestObserver methods 1.694 +NS_IMETHODIMP nsIconChannel::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext) 1.695 +{ 1.696 + if (mListener) 1.697 + return mListener->OnStartRequest(this, aContext); 1.698 + return NS_OK; 1.699 +} 1.700 + 1.701 +NS_IMETHODIMP nsIconChannel::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatus) 1.702 +{ 1.703 + if (mListener) { 1.704 + mListener->OnStopRequest(this, aContext, aStatus); 1.705 + mListener = nullptr; 1.706 + } 1.707 + 1.708 + // Remove from load group 1.709 + if (mLoadGroup) 1.710 + mLoadGroup->RemoveRequest(this, nullptr, aStatus); 1.711 + 1.712 + // Drop notification callbacks to prevent cycles. 1.713 + mCallbacks = nullptr; 1.714 + 1.715 + return NS_OK; 1.716 +} 1.717 + 1.718 +// nsIStreamListener methods 1.719 +NS_IMETHODIMP nsIconChannel::OnDataAvailable(nsIRequest* aRequest, 1.720 + nsISupports* aContext, 1.721 + nsIInputStream* aStream, 1.722 + uint64_t aOffset, 1.723 + uint32_t aCount) 1.724 +{ 1.725 + if (mListener) 1.726 + return mListener->OnDataAvailable(this, aContext, aStream, aOffset, aCount); 1.727 + return NS_OK; 1.728 +}