/image/decoders/icon/win/nsIconChannel.cpp

http://github.com/zpao/v8monkey · C++ · 757 lines · 549 code · 109 blank · 99 comment · 66 complexity · 9ba456cda3bb74e8fa4b3aaf280d89b8 MD5 · raw file

  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. *
  3. * ***** BEGIN LICENSE BLOCK *****
  4. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  5. *
  6. * The contents of this file are subject to the Mozilla Public License Version
  7. * 1.1 (the "License"); you may not use this file except in compliance with
  8. * the License. You may obtain a copy of the License at
  9. * http://www.mozilla.org/MPL/
  10. *
  11. * Software distributed under the License is distributed on an "AS IS" basis,
  12. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  13. * for the specific language governing rights and limitations under the
  14. * License.
  15. *
  16. * The Original Code is mozilla.org code.
  17. *
  18. * The Initial Developer of the Original Code is
  19. * Brian Ryner.
  20. * Portions created by the Initial Developer are Copyright (C) 2000
  21. * the Initial Developer. All Rights Reserved.
  22. *
  23. * Contributor(s):
  24. * Scott MacGregor <mscott@netscape.com>
  25. * Neil Rashbrook <neil@parkwaycc.co.uk>
  26. * Ben Goodger <ben@mozilla.org>
  27. * Siddharth Agarwal <sid.bugzilla@gmail.com>
  28. *
  29. * Alternatively, the contents of this file may be used under the terms of
  30. * either the GNU General Public License Version 2 or later (the "GPL"), or
  31. * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  32. * in which case the provisions of the GPL or the LGPL are applicable instead
  33. * of those above. If you wish to allow use of your version of this file only
  34. * under the terms of either the GPL or the LGPL, and not to allow others to
  35. * use your version of this file under the terms of the MPL, indicate your
  36. * decision by deleting the provisions above and replace them with the notice
  37. * and other provisions required by the GPL or the LGPL. If you do not delete
  38. * the provisions above, a recipient may use your version of this file under
  39. * the terms of any one of the MPL, the GPL or the LGPL.
  40. *
  41. * ***** END LICENSE BLOCK ***** */
  42. #include "mozilla/Util.h"
  43. #include "nsIconChannel.h"
  44. #include "nsIIconURI.h"
  45. #include "nsIServiceManager.h"
  46. #include "nsIInterfaceRequestor.h"
  47. #include "nsIInterfaceRequestorUtils.h"
  48. #include "nsXPIDLString.h"
  49. #include "nsReadableUtils.h"
  50. #include "nsMimeTypes.h"
  51. #include "nsMemory.h"
  52. #include "nsIStringStream.h"
  53. #include "nsIURL.h"
  54. #include "nsNetUtil.h"
  55. #include "nsIFile.h"
  56. #include "nsIFileURL.h"
  57. #include "nsIMIMEService.h"
  58. #include "nsCExternalHandlerService.h"
  59. #include "nsDirectoryServiceDefs.h"
  60. #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
  61. #ifdef _WIN32_WINNT
  62. #undef _WIN32_WINNT
  63. #endif
  64. #define _WIN32_WINNT 0x0600
  65. #endif
  66. // we need windows.h to read out registry information...
  67. #include <windows.h>
  68. #include <shellapi.h>
  69. #include <shlobj.h>
  70. #include <objbase.h>
  71. #include <wchar.h>
  72. using namespace mozilla;
  73. struct ICONFILEHEADER {
  74. PRUint16 ifhReserved;
  75. PRUint16 ifhType;
  76. PRUint16 ifhCount;
  77. };
  78. struct ICONENTRY {
  79. PRInt8 ieWidth;
  80. PRInt8 ieHeight;
  81. PRUint8 ieColors;
  82. PRUint8 ieReserved;
  83. PRUint16 iePlanes;
  84. PRUint16 ieBitCount;
  85. PRUint32 ieSizeImage;
  86. PRUint32 ieFileOffset;
  87. };
  88. #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
  89. typedef HRESULT (WINAPI*SHGetStockIconInfoPtr) (SHSTOCKICONID siid, UINT uFlags, SHSTOCKICONINFO *psii);
  90. // Match stock icons with names
  91. static SHSTOCKICONID GetStockIconIDForName(const nsACString &aStockName)
  92. {
  93. // UAC shield icon
  94. if (aStockName == NS_LITERAL_CSTRING("uac-shield"))
  95. return SIID_SHIELD;
  96. return SIID_INVALID;
  97. }
  98. #endif
  99. // nsIconChannel methods
  100. nsIconChannel::nsIconChannel()
  101. {
  102. }
  103. nsIconChannel::~nsIconChannel()
  104. {}
  105. NS_IMPL_THREADSAFE_ISUPPORTS4(nsIconChannel,
  106. nsIChannel,
  107. nsIRequest,
  108. nsIRequestObserver,
  109. nsIStreamListener)
  110. nsresult nsIconChannel::Init(nsIURI* uri)
  111. {
  112. NS_ASSERTION(uri, "no uri");
  113. mUrl = uri;
  114. mOriginalURI = uri;
  115. nsresult rv;
  116. mPump = do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv);
  117. return rv;
  118. }
  119. ////////////////////////////////////////////////////////////////////////////////
  120. // nsIRequest methods:
  121. NS_IMETHODIMP nsIconChannel::GetName(nsACString &result)
  122. {
  123. return mUrl->GetSpec(result);
  124. }
  125. NS_IMETHODIMP nsIconChannel::IsPending(bool *result)
  126. {
  127. return mPump->IsPending(result);
  128. }
  129. NS_IMETHODIMP nsIconChannel::GetStatus(nsresult *status)
  130. {
  131. return mPump->GetStatus(status);
  132. }
  133. NS_IMETHODIMP nsIconChannel::Cancel(nsresult status)
  134. {
  135. return mPump->Cancel(status);
  136. }
  137. NS_IMETHODIMP nsIconChannel::Suspend(void)
  138. {
  139. return mPump->Suspend();
  140. }
  141. NS_IMETHODIMP nsIconChannel::Resume(void)
  142. {
  143. return mPump->Resume();
  144. }
  145. NS_IMETHODIMP nsIconChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
  146. {
  147. *aLoadGroup = mLoadGroup;
  148. NS_IF_ADDREF(*aLoadGroup);
  149. return NS_OK;
  150. }
  151. NS_IMETHODIMP nsIconChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
  152. {
  153. mLoadGroup = aLoadGroup;
  154. return NS_OK;
  155. }
  156. NS_IMETHODIMP nsIconChannel::GetLoadFlags(PRUint32 *aLoadAttributes)
  157. {
  158. return mPump->GetLoadFlags(aLoadAttributes);
  159. }
  160. NS_IMETHODIMP nsIconChannel::SetLoadFlags(PRUint32 aLoadAttributes)
  161. {
  162. return mPump->SetLoadFlags(aLoadAttributes);
  163. }
  164. ////////////////////////////////////////////////////////////////////////////////
  165. // nsIChannel methods:
  166. NS_IMETHODIMP nsIconChannel::GetOriginalURI(nsIURI* *aURI)
  167. {
  168. *aURI = mOriginalURI;
  169. NS_ADDREF(*aURI);
  170. return NS_OK;
  171. }
  172. NS_IMETHODIMP nsIconChannel::SetOriginalURI(nsIURI* aURI)
  173. {
  174. NS_ENSURE_ARG_POINTER(aURI);
  175. mOriginalURI = aURI;
  176. return NS_OK;
  177. }
  178. NS_IMETHODIMP nsIconChannel::GetURI(nsIURI* *aURI)
  179. {
  180. *aURI = mUrl;
  181. NS_IF_ADDREF(*aURI);
  182. return NS_OK;
  183. }
  184. NS_IMETHODIMP
  185. nsIconChannel::Open(nsIInputStream **_retval)
  186. {
  187. return MakeInputStream(_retval, false);
  188. }
  189. nsresult nsIconChannel::ExtractIconInfoFromUrl(nsIFile ** aLocalFile, PRUint32 * aDesiredImageSize, nsCString &aContentType, nsCString &aFileExtension)
  190. {
  191. nsresult rv = NS_OK;
  192. nsCOMPtr<nsIMozIconURI> iconURI (do_QueryInterface(mUrl, &rv));
  193. NS_ENSURE_SUCCESS(rv, rv);
  194. iconURI->GetImageSize(aDesiredImageSize);
  195. iconURI->GetContentType(aContentType);
  196. iconURI->GetFileExtension(aFileExtension);
  197. nsCOMPtr<nsIURL> url;
  198. rv = iconURI->GetIconURL(getter_AddRefs(url));
  199. if (NS_FAILED(rv) || !url) return NS_OK;
  200. nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(url, &rv);
  201. if (NS_FAILED(rv) || !fileURL) return NS_OK;
  202. nsCOMPtr<nsIFile> file;
  203. rv = fileURL->GetFile(getter_AddRefs(file));
  204. if (NS_FAILED(rv) || !file) return NS_OK;
  205. return file->Clone(aLocalFile);
  206. }
  207. NS_IMETHODIMP nsIconChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt)
  208. {
  209. nsCOMPtr<nsIInputStream> inStream;
  210. nsresult rv = MakeInputStream(getter_AddRefs(inStream), true);
  211. if (NS_FAILED(rv))
  212. return rv;
  213. // Init our streampump
  214. rv = mPump->Init(inStream, PRInt64(-1), PRInt64(-1), 0, 0, false);
  215. if (NS_FAILED(rv))
  216. return rv;
  217. rv = mPump->AsyncRead(this, ctxt);
  218. if (NS_SUCCEEDED(rv)) {
  219. // Store our real listener
  220. mListener = aListener;
  221. // Add ourself to the load group, if available
  222. if (mLoadGroup)
  223. mLoadGroup->AddRequest(this, nsnull);
  224. }
  225. return rv;
  226. }
  227. static DWORD GetSpecialFolderIcon(nsIFile* aFile, int aFolder, SHFILEINFOW* aSFI, UINT aInfoFlags)
  228. {
  229. DWORD shellResult = 0;
  230. if (!aFile)
  231. return shellResult;
  232. PRUnichar fileNativePath[MAX_PATH];
  233. nsAutoString fileNativePathStr;
  234. aFile->GetPath(fileNativePathStr);
  235. ::GetShortPathNameW(fileNativePathStr.get(), fileNativePath, ArrayLength(fileNativePath));
  236. LPITEMIDLIST idList;
  237. HRESULT hr = ::SHGetSpecialFolderLocation(NULL, aFolder, &idList);
  238. if (SUCCEEDED(hr)) {
  239. PRUnichar specialNativePath[MAX_PATH];
  240. ::SHGetPathFromIDListW(idList, specialNativePath);
  241. ::GetShortPathNameW(specialNativePath, specialNativePath, ArrayLength(specialNativePath));
  242. if (!wcsicmp(fileNativePath, specialNativePath)) {
  243. aInfoFlags |= (SHGFI_PIDL | SHGFI_SYSICONINDEX);
  244. shellResult = ::SHGetFileInfoW((LPCWSTR)(LPCITEMIDLIST)idList, 0, aSFI,
  245. sizeof(*aSFI), aInfoFlags);
  246. }
  247. }
  248. CoTaskMemFree(idList);
  249. return shellResult;
  250. }
  251. static UINT GetSizeInfoFlag(PRUint32 aDesiredImageSize)
  252. {
  253. UINT infoFlag;
  254. if (aDesiredImageSize > 16)
  255. infoFlag = SHGFI_SHELLICONSIZE;
  256. else
  257. infoFlag = SHGFI_SMALLICON;
  258. return infoFlag;
  259. }
  260. nsresult nsIconChannel::GetHIconFromFile(HICON *hIcon)
  261. {
  262. nsXPIDLCString contentType;
  263. nsCString fileExt;
  264. nsCOMPtr<nsIFile> localFile; // file we want an icon for
  265. PRUint32 desiredImageSize;
  266. nsresult rv = ExtractIconInfoFromUrl(getter_AddRefs(localFile), &desiredImageSize, contentType, fileExt);
  267. NS_ENSURE_SUCCESS(rv, rv);
  268. // if the file exists, we are going to use it's real attributes...otherwise we only want to use it for it's extension...
  269. SHFILEINFOW sfi;
  270. UINT infoFlags = SHGFI_ICON;
  271. bool fileExists = false;
  272. nsAutoString filePath;
  273. CopyASCIItoUTF16(fileExt, filePath);
  274. if (localFile)
  275. {
  276. rv = localFile->Normalize();
  277. NS_ENSURE_SUCCESS(rv, rv);
  278. localFile->GetPath(filePath);
  279. if (filePath.Length() < 2 || filePath[1] != ':')
  280. return NS_ERROR_MALFORMED_URI; // UNC
  281. if (filePath.Last() == ':')
  282. filePath.Append('\\');
  283. else {
  284. localFile->Exists(&fileExists);
  285. if (!fileExists)
  286. localFile->GetLeafName(filePath);
  287. }
  288. }
  289. if (!fileExists)
  290. infoFlags |= SHGFI_USEFILEATTRIBUTES;
  291. infoFlags |= GetSizeInfoFlag(desiredImageSize);
  292. // if we have a content type... then use it! but for existing files, we want
  293. // to show their real icon.
  294. if (!fileExists && !contentType.IsEmpty())
  295. {
  296. nsCOMPtr<nsIMIMEService> mimeService (do_GetService(NS_MIMESERVICE_CONTRACTID, &rv));
  297. NS_ENSURE_SUCCESS(rv, rv);
  298. nsCAutoString defFileExt;
  299. mimeService->GetPrimaryExtension(contentType, fileExt, defFileExt);
  300. // If the mime service does not know about this mime type, we show
  301. // the generic icon.
  302. // In any case, we need to insert a '.' before the extension.
  303. filePath = NS_LITERAL_STRING(".") + NS_ConvertUTF8toUTF16(defFileExt);
  304. }
  305. // Is this the "Desktop" folder?
  306. DWORD shellResult = GetSpecialFolderIcon(localFile, CSIDL_DESKTOP, &sfi, infoFlags);
  307. if (!shellResult) {
  308. // Is this the "My Documents" folder?
  309. shellResult = GetSpecialFolderIcon(localFile, CSIDL_PERSONAL, &sfi, infoFlags);
  310. }
  311. // There are other "Special Folders" and Namespace entities that we are not
  312. // fetching icons for, see:
  313. // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/enums/csidl.asp
  314. // If we ever need to get them, code to do so would be inserted here.
  315. // Not a special folder, or something else failed above.
  316. if (!shellResult)
  317. shellResult = ::SHGetFileInfoW(filePath.get(),
  318. FILE_ATTRIBUTE_ARCHIVE, &sfi, sizeof(sfi), infoFlags);
  319. if (shellResult && sfi.hIcon)
  320. *hIcon = sfi.hIcon;
  321. else
  322. rv = NS_ERROR_NOT_AVAILABLE;
  323. return rv;
  324. }
  325. #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
  326. nsresult nsIconChannel::GetStockHIcon(nsIMozIconURI *aIconURI, HICON *hIcon)
  327. {
  328. nsresult rv = NS_OK;
  329. // We can only do this on Vista or above
  330. HMODULE hShellDLL = ::LoadLibraryW(L"shell32.dll");
  331. SHGetStockIconInfoPtr pSHGetStockIconInfo =
  332. (SHGetStockIconInfoPtr) ::GetProcAddress(hShellDLL, "SHGetStockIconInfo");
  333. if (pSHGetStockIconInfo)
  334. {
  335. PRUint32 desiredImageSize;
  336. aIconURI->GetImageSize(&desiredImageSize);
  337. nsCAutoString stockIcon;
  338. aIconURI->GetStockIcon(stockIcon);
  339. SHSTOCKICONID stockIconID = GetStockIconIDForName(stockIcon);
  340. if (stockIconID == SIID_INVALID)
  341. return NS_ERROR_NOT_AVAILABLE;
  342. UINT infoFlags = SHGSI_ICON;
  343. infoFlags |= GetSizeInfoFlag(desiredImageSize);
  344. SHSTOCKICONINFO sii = {0};
  345. sii.cbSize = sizeof(sii);
  346. HRESULT hr = pSHGetStockIconInfo(stockIconID, infoFlags, &sii);
  347. if (SUCCEEDED(hr))
  348. *hIcon = sii.hIcon;
  349. else
  350. rv = NS_ERROR_FAILURE;
  351. }
  352. else
  353. {
  354. rv = NS_ERROR_NOT_AVAILABLE;
  355. }
  356. if (hShellDLL)
  357. ::FreeLibrary(hShellDLL);
  358. return rv;
  359. }
  360. #endif
  361. // Given a BITMAPINFOHEADER, returns the size of the color table.
  362. static int GetColorTableSize(BITMAPINFOHEADER* aHeader)
  363. {
  364. int colorTableSize = -1;
  365. // http://msdn.microsoft.com/en-us/library/dd183376%28v=VS.85%29.aspx
  366. switch (aHeader->biBitCount) {
  367. case 0:
  368. colorTableSize = 0;
  369. break;
  370. case 1:
  371. colorTableSize = 2 * sizeof(RGBQUAD);
  372. break;
  373. case 4:
  374. case 8:
  375. {
  376. // The maximum possible size for the color table is 2**bpp, so check for
  377. // that and fail if we're not in those bounds
  378. unsigned int maxEntries = 1 << (aHeader->biBitCount);
  379. if (aHeader->biClrUsed > 0 && aHeader->biClrUsed <= maxEntries)
  380. colorTableSize = aHeader->biClrUsed * sizeof(RGBQUAD);
  381. else if (aHeader->biClrUsed == 0)
  382. colorTableSize = maxEntries * sizeof(RGBQUAD);
  383. break;
  384. }
  385. case 16:
  386. case 32:
  387. // If we have BI_BITFIELDS compression, we would normally need 3 DWORDS for
  388. // the bitfields mask which would be stored in the color table; However,
  389. // we instead force the bitmap to request data of type BI_RGB so the color
  390. // table should be of size 0.
  391. // Setting aHeader->biCompression = BI_RGB forces the later call to
  392. // GetDIBits to return to us BI_RGB data.
  393. if (aHeader->biCompression == BI_BITFIELDS) {
  394. aHeader->biCompression = BI_RGB;
  395. }
  396. colorTableSize = 0;
  397. break;
  398. case 24:
  399. colorTableSize = 0;
  400. break;
  401. }
  402. if (colorTableSize < 0)
  403. NS_WARNING("Unable to figure out the color table size for this bitmap");
  404. return colorTableSize;
  405. }
  406. // Given a header and a size, creates a freshly allocated BITMAPINFO structure.
  407. // It is the caller's responsibility to null-check and delete the structure.
  408. static BITMAPINFO* CreateBitmapInfo(BITMAPINFOHEADER* aHeader,
  409. size_t aColorTableSize)
  410. {
  411. BITMAPINFO* bmi = (BITMAPINFO*) ::operator new(sizeof(BITMAPINFOHEADER) +
  412. aColorTableSize,
  413. mozilla::fallible_t());
  414. if (bmi) {
  415. memcpy(bmi, aHeader, sizeof(BITMAPINFOHEADER));
  416. memset(bmi->bmiColors, 0, aColorTableSize);
  417. }
  418. return bmi;
  419. }
  420. nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, bool nonBlocking)
  421. {
  422. // Check whether the icon requested's a file icon or a stock icon
  423. nsresult rv = NS_ERROR_NOT_AVAILABLE;
  424. // GetDIBits does not exist on windows mobile.
  425. HICON hIcon = NULL;
  426. #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
  427. nsCOMPtr<nsIMozIconURI> iconURI(do_QueryInterface(mUrl, &rv));
  428. NS_ENSURE_SUCCESS(rv, rv);
  429. nsCAutoString stockIcon;
  430. iconURI->GetStockIcon(stockIcon);
  431. if (!stockIcon.IsEmpty())
  432. rv = GetStockHIcon(iconURI, &hIcon);
  433. else
  434. #endif
  435. rv = GetHIconFromFile(&hIcon);
  436. NS_ENSURE_SUCCESS(rv, rv);
  437. if (hIcon)
  438. {
  439. // we got a handle to an icon. Now we want to get a bitmap for the icon using GetIconInfo....
  440. ICONINFO iconInfo;
  441. if (GetIconInfo(hIcon, &iconInfo))
  442. {
  443. // we got the bitmaps, first find out their size
  444. HDC hDC = CreateCompatibleDC(NULL); // get a device context for the screen.
  445. BITMAPINFOHEADER maskHeader = {sizeof(BITMAPINFOHEADER)};
  446. BITMAPINFOHEADER colorHeader = {sizeof(BITMAPINFOHEADER)};
  447. int colorTableSize, maskTableSize;
  448. if (GetDIBits(hDC, iconInfo.hbmMask, 0, 0, NULL, (BITMAPINFO*)&maskHeader, DIB_RGB_COLORS) &&
  449. GetDIBits(hDC, iconInfo.hbmColor, 0, 0, NULL, (BITMAPINFO*)&colorHeader, DIB_RGB_COLORS) &&
  450. maskHeader.biHeight == colorHeader.biHeight &&
  451. maskHeader.biWidth == colorHeader.biWidth &&
  452. colorHeader.biBitCount > 8 &&
  453. colorHeader.biSizeImage > 0 &&
  454. maskHeader.biSizeImage > 0 &&
  455. (colorTableSize = GetColorTableSize(&colorHeader)) >= 0 &&
  456. (maskTableSize = GetColorTableSize(&maskHeader)) >= 0) {
  457. PRUint32 iconSize = sizeof(ICONFILEHEADER) +
  458. sizeof(ICONENTRY) +
  459. sizeof(BITMAPINFOHEADER) +
  460. colorHeader.biSizeImage +
  461. maskHeader.biSizeImage;
  462. char *buffer = new char[iconSize];
  463. if (!buffer)
  464. rv = NS_ERROR_OUT_OF_MEMORY;
  465. else {
  466. char *whereTo = buffer;
  467. int howMuch;
  468. // the data starts with an icon file header
  469. ICONFILEHEADER iconHeader;
  470. iconHeader.ifhReserved = 0;
  471. iconHeader.ifhType = 1;
  472. iconHeader.ifhCount = 1;
  473. howMuch = sizeof(ICONFILEHEADER);
  474. memcpy(whereTo, &iconHeader, howMuch);
  475. whereTo += howMuch;
  476. // followed by the single icon entry
  477. ICONENTRY iconEntry;
  478. iconEntry.ieWidth = colorHeader.biWidth;
  479. iconEntry.ieHeight = colorHeader.biHeight;
  480. iconEntry.ieColors = 0;
  481. iconEntry.ieReserved = 0;
  482. iconEntry.iePlanes = 1;
  483. iconEntry.ieBitCount = colorHeader.biBitCount;
  484. iconEntry.ieSizeImage = sizeof(BITMAPINFOHEADER) +
  485. colorHeader.biSizeImage +
  486. maskHeader.biSizeImage;
  487. iconEntry.ieFileOffset = sizeof(ICONFILEHEADER) + sizeof(ICONENTRY);
  488. howMuch = sizeof(ICONENTRY);
  489. memcpy(whereTo, &iconEntry, howMuch);
  490. whereTo += howMuch;
  491. // followed by the bitmap info header
  492. // (doubling the height because icons have two bitmaps)
  493. colorHeader.biHeight *= 2;
  494. colorHeader.biSizeImage += maskHeader.biSizeImage;
  495. howMuch = sizeof(BITMAPINFOHEADER);
  496. memcpy(whereTo, &colorHeader, howMuch);
  497. whereTo += howMuch;
  498. colorHeader.biHeight /= 2;
  499. colorHeader.biSizeImage -= maskHeader.biSizeImage;
  500. // followed by the XOR bitmap data (colorHeader)
  501. // (you'd expect the color table to come here, but it apparently doesn't)
  502. BITMAPINFO* colorInfo = CreateBitmapInfo(&colorHeader, colorTableSize);
  503. if (colorInfo && GetDIBits(hDC, iconInfo.hbmColor, 0,
  504. colorHeader.biHeight, whereTo, colorInfo,
  505. DIB_RGB_COLORS)) {
  506. whereTo += colorHeader.biSizeImage;
  507. // and finally the AND bitmap data (maskHeader)
  508. BITMAPINFO* maskInfo = CreateBitmapInfo(&maskHeader, maskTableSize);
  509. if (maskInfo && GetDIBits(hDC, iconInfo.hbmMask, 0,
  510. maskHeader.biHeight, whereTo, maskInfo,
  511. DIB_RGB_COLORS)) {
  512. // Now, create a pipe and stuff our data into it
  513. nsCOMPtr<nsIInputStream> inStream;
  514. nsCOMPtr<nsIOutputStream> outStream;
  515. rv = NS_NewPipe(getter_AddRefs(inStream), getter_AddRefs(outStream),
  516. iconSize, iconSize, nonBlocking);
  517. if (NS_SUCCEEDED(rv)) {
  518. PRUint32 written;
  519. rv = outStream->Write(buffer, iconSize, &written);
  520. if (NS_SUCCEEDED(rv)) {
  521. NS_ADDREF(*_retval = inStream);
  522. }
  523. }
  524. } // if we got bitmap bits
  525. delete maskInfo;
  526. } // if we got mask bits
  527. delete colorInfo;
  528. delete [] buffer;
  529. } // if we allocated the buffer
  530. } // if we got mask size
  531. DeleteDC(hDC);
  532. DeleteObject(iconInfo.hbmColor);
  533. DeleteObject(iconInfo.hbmMask);
  534. } // if we got icon info
  535. DestroyIcon(hIcon);
  536. } // if we got an hIcon
  537. // If we didn't make a stream, then fail.
  538. if (!*_retval && NS_SUCCEEDED(rv))
  539. rv = NS_ERROR_NOT_AVAILABLE;
  540. return rv;
  541. }
  542. NS_IMETHODIMP nsIconChannel::GetContentType(nsACString &aContentType)
  543. {
  544. aContentType.AssignLiteral("image/x-icon");
  545. return NS_OK;
  546. }
  547. NS_IMETHODIMP
  548. nsIconChannel::SetContentType(const nsACString &aContentType)
  549. {
  550. // It doesn't make sense to set the content-type on this type
  551. // of channel...
  552. return NS_ERROR_FAILURE;
  553. }
  554. NS_IMETHODIMP nsIconChannel::GetContentCharset(nsACString &aContentCharset)
  555. {
  556. aContentCharset.Truncate();
  557. return NS_OK;
  558. }
  559. NS_IMETHODIMP
  560. nsIconChannel::SetContentCharset(const nsACString &aContentCharset)
  561. {
  562. // It doesn't make sense to set the content-charset on this type
  563. // of channel...
  564. return NS_ERROR_FAILURE;
  565. }
  566. NS_IMETHODIMP
  567. nsIconChannel::GetContentDisposition(PRUint32 *aContentDisposition)
  568. {
  569. return NS_ERROR_NOT_AVAILABLE;
  570. }
  571. NS_IMETHODIMP
  572. nsIconChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
  573. {
  574. return NS_ERROR_NOT_AVAILABLE;
  575. }
  576. NS_IMETHODIMP
  577. nsIconChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
  578. {
  579. return NS_ERROR_NOT_AVAILABLE;
  580. }
  581. NS_IMETHODIMP nsIconChannel::GetContentLength(PRInt32 *aContentLength)
  582. {
  583. *aContentLength = mContentLength;
  584. return NS_OK;
  585. }
  586. NS_IMETHODIMP nsIconChannel::SetContentLength(PRInt32 aContentLength)
  587. {
  588. NS_NOTREACHED("nsIconChannel::SetContentLength");
  589. return NS_ERROR_NOT_IMPLEMENTED;
  590. }
  591. NS_IMETHODIMP nsIconChannel::GetOwner(nsISupports* *aOwner)
  592. {
  593. *aOwner = mOwner.get();
  594. NS_IF_ADDREF(*aOwner);
  595. return NS_OK;
  596. }
  597. NS_IMETHODIMP nsIconChannel::SetOwner(nsISupports* aOwner)
  598. {
  599. mOwner = aOwner;
  600. return NS_OK;
  601. }
  602. NS_IMETHODIMP nsIconChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aNotificationCallbacks)
  603. {
  604. *aNotificationCallbacks = mCallbacks.get();
  605. NS_IF_ADDREF(*aNotificationCallbacks);
  606. return NS_OK;
  607. }
  608. NS_IMETHODIMP nsIconChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
  609. {
  610. mCallbacks = aNotificationCallbacks;
  611. return NS_OK;
  612. }
  613. NS_IMETHODIMP nsIconChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
  614. {
  615. *aSecurityInfo = nsnull;
  616. return NS_OK;
  617. }
  618. // nsIRequestObserver methods
  619. NS_IMETHODIMP nsIconChannel::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
  620. {
  621. if (mListener)
  622. return mListener->OnStartRequest(this, aContext);
  623. return NS_OK;
  624. }
  625. NS_IMETHODIMP nsIconChannel::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatus)
  626. {
  627. if (mListener) {
  628. mListener->OnStopRequest(this, aContext, aStatus);
  629. mListener = nsnull;
  630. }
  631. // Remove from load group
  632. if (mLoadGroup)
  633. mLoadGroup->RemoveRequest(this, nsnull, aStatus);
  634. // Drop notification callbacks to prevent cycles.
  635. mCallbacks = nsnull;
  636. return NS_OK;
  637. }
  638. // nsIStreamListener methods
  639. NS_IMETHODIMP nsIconChannel::OnDataAvailable(nsIRequest* aRequest,
  640. nsISupports* aContext,
  641. nsIInputStream* aStream,
  642. PRUint32 aOffset,
  643. PRUint32 aCount)
  644. {
  645. if (mListener)
  646. return mListener->OnDataAvailable(this, aContext, aStream, aOffset, aCount);
  647. return NS_OK;
  648. }