From 08f99b052909a65f8a314429c7017571fc9dbff2 Mon Sep 17 00:00:00 2001 From: Drew Willcoxon Date: Fri, 25 Jun 2010 14:06:14 -0700 Subject: [PATCH] Bug 573430 - nsIFaviconService.getFaviconData should not fail when passed the default favicon. r=mak --- .../places/src/nsFaviconService.cpp | 61 ++++++++++++++++++- .../components/places/src/nsFaviconService.h | 8 +++ .../places/tests/unit/test_favicons.js | 22 +++++++ 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/toolkit/components/places/src/nsFaviconService.cpp b/toolkit/components/places/src/nsFaviconService.cpp index db709ef10752..6bbd08f2be22 100644 --- a/toolkit/components/places/src/nsFaviconService.cpp +++ b/toolkit/components/places/src/nsFaviconService.cpp @@ -83,6 +83,10 @@ */ #define MAX_FAVICON_EXPIRATION ((PRTime)7 * 24 * 60 * 60 * PR_USEC_PER_SEC) +// The MIME type of the default favicon and favicons created by +// OptimizeFaviconImage. +#define DEFAULT_MIME_TYPE "image/png" + using namespace mozilla::places; /** @@ -717,8 +721,33 @@ nsFaviconService::GetFaviconData(nsIURI* aFaviconURI, nsACString& aMimeType, NS_ENSURE_ARG_POINTER(aDataLen); NS_ENSURE_ARG_POINTER(aData); + nsCOMPtr defaultFaviconURI; + nsresult rv = GetDefaultFavicon(getter_AddRefs(defaultFaviconURI)); + NS_ENSURE_SUCCESS(rv, rv); + + PRBool isDefaultFavicon = PR_FALSE; + rv = defaultFaviconURI->Equals(aFaviconURI, &isDefaultFavicon); + NS_ENSURE_SUCCESS(rv, rv); + + // If we're getting the default favicon, we need to handle it separately since + // it's not in the database. + if (isDefaultFavicon) { + nsCAutoString defaultData; + rv = GetDefaultFaviconData(defaultData); + NS_ENSURE_SUCCESS(rv, rv); + + PRUint8* bytes = reinterpret_cast(ToNewCString(defaultData)); + NS_ENSURE_STATE(bytes); + + *aData = bytes; + *aDataLen = defaultData.Length(); + aMimeType.AssignLiteral(DEFAULT_MIME_TYPE); + + return NS_OK; + } + DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetData); - nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI); + rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI); NS_ENSURE_SUCCESS(rv, rv); PRBool hasResult = PR_FALSE; @@ -732,6 +761,33 @@ nsFaviconService::GetFaviconData(nsIURI* aFaviconURI, nsACString& aMimeType, } +nsresult +nsFaviconService::GetDefaultFaviconData(nsCString& byteStr) +{ + if (mDefaultFaviconData.IsEmpty()) { + nsCOMPtr defaultFaviconURI; + nsresult rv = GetDefaultFavicon(getter_AddRefs(defaultFaviconURI)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr istream; + rv = NS_OpenURI(getter_AddRefs(istream), defaultFaviconURI); + NS_ENSURE_SUCCESS(rv, rv); + + rv = NS_ConsumeStream(istream, PR_UINT32_MAX, mDefaultFaviconData); + NS_ENSURE_SUCCESS(rv, rv); + + rv = istream->Close(); + NS_ENSURE_SUCCESS(rv, rv); + + if (mDefaultFaviconData.IsEmpty()) + return NS_ERROR_UNEXPECTED; + } + + byteStr.Assign(mDefaultFaviconData); + return NS_OK; +} + + NS_IMETHODIMP nsFaviconService::GetFaviconDataAsDataURL(nsIURI* aFaviconURI, nsAString& aDataURL) @@ -963,7 +1019,6 @@ nsFaviconService::OptimizeFaviconImage(const PRUint8* aData, PRUint32 aDataLen, nsACString& aNewMimeType) { nsresult rv; - nsCOMPtr imgtool = do_CreateInstance("@mozilla.org/image/tools;1"); @@ -978,7 +1033,7 @@ nsFaviconService::OptimizeFaviconImage(const PRUint8* aData, PRUint32 aDataLen, rv = imgtool->DecodeImageData(stream, aMimeType, getter_AddRefs(container)); NS_ENSURE_SUCCESS(rv, rv); - aNewMimeType.AssignLiteral("image/png"); + aNewMimeType.AssignLiteral(DEFAULT_MIME_TYPE); // scale and recompress nsCOMPtr iconStream; diff --git a/toolkit/components/places/src/nsFaviconService.h b/toolkit/components/places/src/nsFaviconService.h index c87b986afc3a..da9a88738b32 100644 --- a/toolkit/components/places/src/nsFaviconService.h +++ b/toolkit/components/places/src/nsFaviconService.h @@ -222,6 +222,14 @@ private: friend class FaviconLoadListener; bool mShuttingDown; + + // Caches the content of the default favicon if it's not already cached and + // copies it into byteStr. + nsresult GetDefaultFaviconData(nsCString& byteStr); + + // A string of bytes caching the default favicon's content. Empty if not yet + // cached. Rather than accessing this directly, use GetDefaultFaviconData. + nsCString mDefaultFaviconData; }; #define FAVICON_ANNOTATION_NAME "favicon" diff --git a/toolkit/components/places/tests/unit/test_favicons.js b/toolkit/components/places/tests/unit/test_favicons.js index fad67720ec23..c0dd2cf27294 100644 --- a/toolkit/components/places/tests/unit/test_favicons.js +++ b/toolkit/components/places/tests/unit/test_favicons.js @@ -392,6 +392,28 @@ iconsvc.removeFailedFavicon(faviconURI); do_check_false(iconsvc.isFailedFavicon(faviconURI)); +/* ========== 13 ========== */ +testnum++; +testdesc = "test getFaviconData on the default favicon "; + +outMimeType = {}; +outData = iconsvc.getFaviconData(iconsvc.defaultFavicon, outMimeType); +do_check_eq(outMimeType.value, "image/png"); + +// Read in the icon and compare it to what the API returned above. +var istream = NetUtil.newChannel(iconsvc.defaultFavicon).open(); +var bistream = Cc["@mozilla.org/binaryinputstream;1"]. + createInstance(Ci.nsIBinaryInputStream); +bistream.setInputStream(istream); +expectedData = []; +var avail; +while (avail = bistream.available()) { + expectedData = expectedData.concat(bistream.readByteArray(avail)); +} +bistream.close(); +checkArrays(outData, expectedData); + + /* ========== end ========== */ } catch (e) {