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