PageRenderTime 69ms CodeModel.GetById 19ms app.highlight 44ms RepoModel.GetById 1ms app.codeStats 1ms

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