LCOV - code coverage report
Current view: directory - toolkit/components/places - nsFaviconService.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 531 463 87.2 %
Date: 2012-06-02 Functions: 40 37 92.5 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Places.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Google Inc.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2005
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Brett Wilson <brettw@gmail.com> (original author)
      24                 :  *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
      25                 :  *   Shawn Wilsher <me@shawnwilsher.com>
      26                 :  *   Marco Bonardo <mak77@bonardo.net>
      27                 :  *   Richard Newman <rnewman@mozilla.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                 : /**
      44                 :  * This is the favicon service, which stores favicons for web pages with your
      45                 :  * history as you browse. It is also used to save the favicons for bookmarks.
      46                 :  *
      47                 :  * DANGER: The history query system makes assumptions about the favicon storage
      48                 :  * so that icons can be quickly generated for history/bookmark result sets. If
      49                 :  * you change the database layout at all, you will have to update both services.
      50                 :  */
      51                 : 
      52                 : #include "nsFaviconService.h"
      53                 : 
      54                 : #include "nsNavHistory.h"
      55                 : #include "nsPlacesMacros.h"
      56                 : #include "Helpers.h"
      57                 : #include "AsyncFaviconHelpers.h"
      58                 : 
      59                 : #include "nsNetUtil.h"
      60                 : #include "nsReadableUtils.h"
      61                 : #include "nsStreamUtils.h"
      62                 : #include "nsStringStream.h"
      63                 : #include "plbase64.h"
      64                 : #include "nsIClassInfoImpl.h"
      65                 : #include "mozilla/Preferences.h"
      66                 : #include "mozilla/Util.h"
      67                 : 
      68                 : // For large favicons optimization.
      69                 : #include "imgITools.h"
      70                 : #include "imgIContainer.h"
      71                 : 
      72                 : // Default value for mOptimizedIconDimension
      73                 : #define OPTIMIZED_FAVICON_DIMENSION 16
      74                 : 
      75                 : #define MAX_FAVICON_CACHE_SIZE 256
      76                 : #define FAVICON_CACHE_REDUCE_COUNT 64
      77                 : 
      78                 : #define MAX_UNASSOCIATED_FAVICONS 64
      79                 : 
      80                 : // When replaceFaviconData is called, we store the icons in an in-memory cache
      81                 : // instead of in storage. Icons in the cache are expired according to this
      82                 : // interval.
      83                 : #define UNASSOCIATED_ICON_EXPIRY_INTERVAL 60000
      84                 : 
      85                 : // The MIME type of the default favicon and favicons created by
      86                 : // OptimizeFaviconImage.
      87                 : #define DEFAULT_MIME_TYPE "image/png"
      88                 : 
      89                 : using namespace mozilla;
      90                 : using namespace mozilla::places;
      91                 : 
      92                 : /**
      93                 :  * Used to notify a topic to system observers on async execute completion.
      94                 :  * Will throw on error.
      95                 :  */
      96                 : class ExpireFaviconsStatementCallbackNotifier : public AsyncStatementCallback
      97               4 : {
      98                 : public:
      99                 :   ExpireFaviconsStatementCallbackNotifier(bool* aFaviconsExpirationRunning);
     100                 :   NS_IMETHOD HandleCompletion(PRUint16 aReason);
     101                 : 
     102                 : private:
     103                 :   bool* mFaviconsExpirationRunning;
     104                 : };
     105                 : 
     106                 : 
     107              96 : PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsFaviconService, gFaviconService)
     108                 : 
     109                 : NS_IMPL_CLASSINFO(nsFaviconService, NULL, 0, NS_FAVICONSERVICE_CID)
     110            1812 : NS_IMPL_ISUPPORTS3_CI(
     111                 :   nsFaviconService
     112                 : , nsIFaviconService
     113                 : , mozIAsyncFavicons
     114                 : , nsITimerCallback
     115              79 : )
     116                 : 
     117              48 : nsFaviconService::nsFaviconService()
     118                 :   : mFaviconsExpirationRunning(false)
     119                 :   , mOptimizedIconDimension(OPTIMIZED_FAVICON_DIMENSION)
     120              48 :   , mFailedFaviconSerial(0)
     121                 : {
     122              48 :   NS_ASSERTION(!gFaviconService,
     123                 :                "Attempting to create two instances of the service!");
     124              48 :   gFaviconService = this;
     125              48 : }
     126                 : 
     127                 : 
     128              96 : nsFaviconService::~nsFaviconService()
     129                 : {
     130              48 :   NS_ASSERTION(gFaviconService == this,
     131                 :                "Deleting a non-singleton instance of the service");
     132              48 :   if (gFaviconService == this)
     133              48 :     gFaviconService = nsnull;
     134              48 : }
     135                 : 
     136                 : 
     137                 : nsresult
     138              48 : nsFaviconService::Init()
     139                 : {
     140              48 :   mDB = Database::GetDatabase();
     141              48 :   NS_ENSURE_STATE(mDB);
     142                 : 
     143                 :   // Init failed favicon cache.
     144              48 :   if (!mFailedFavicons.Init(MAX_FAVICON_CACHE_SIZE))
     145               0 :     return NS_ERROR_OUT_OF_MEMORY;
     146                 : 
     147              48 :   if (!mUnassociatedIcons.Init(MAX_UNASSOCIATED_FAVICONS))
     148               0 :     return NS_ERROR_OUT_OF_MEMORY;
     149                 : 
     150                 :   mOptimizedIconDimension = Preferences::GetInt(
     151                 :     "places.favicons.optimizeToDimension", OPTIMIZED_FAVICON_DIMENSION
     152              48 :   );
     153                 : 
     154              48 :   mExpireUnassociatedIconsTimer = do_CreateInstance("@mozilla.org/timer;1");
     155              48 :   NS_ENSURE_STATE(mExpireUnassociatedIconsTimer);
     156                 : 
     157              48 :   return NS_OK;
     158                 : }
     159                 : 
     160                 : NS_IMETHODIMP
     161               1 : nsFaviconService::ExpireAllFavicons()
     162                 : {
     163               1 :   mFaviconsExpirationRunning = true;
     164                 :   nsCOMPtr<mozIStorageAsyncStatement> unlinkIconsStmt = mDB->GetAsyncStatement(
     165                 :     "UPDATE moz_places "
     166                 :     "SET favicon_id = NULL "
     167                 :     "WHERE favicon_id NOT NULL"
     168               2 :   );
     169               1 :   NS_ENSURE_STATE(unlinkIconsStmt);
     170                 :   nsCOMPtr<mozIStorageAsyncStatement> removeIconsStmt = mDB->GetAsyncStatement(
     171                 :     "DELETE FROM moz_favicons WHERE id NOT IN ("
     172                 :       "SELECT favicon_id FROM moz_places WHERE favicon_id NOT NULL "
     173                 :     ")"
     174               2 :   );
     175               1 :   NS_ENSURE_STATE(removeIconsStmt);
     176                 : 
     177                 :   mozIStorageBaseStatement* stmts[] = {
     178               1 :     unlinkIconsStmt.get()
     179               1 :   , removeIconsStmt.get()
     180               3 :   };
     181               2 :   nsCOMPtr<mozIStoragePendingStatement> ps;
     182                 :   nsRefPtr<ExpireFaviconsStatementCallbackNotifier> callback =
     183               2 :     new ExpireFaviconsStatementCallbackNotifier(&mFaviconsExpirationRunning);
     184               1 :   nsresult rv = mDB->MainConn()->ExecuteAsync(
     185               1 :     stmts, ArrayLength(stmts), callback, getter_AddRefs(ps)
     186               1 :   );
     187               1 :   NS_ENSURE_SUCCESS(rv, rv);
     188                 : 
     189               1 :   return NS_OK;
     190                 : }
     191                 : 
     192                 : ////////////////////////////////////////////////////////////////////////////////
     193                 : //// nsITimerCallback
     194                 : 
     195                 : static PLDHashOperator
     196               0 : ExpireNonrecentUnassociatedIconsEnumerator(
     197                 :   UnassociatedIconHashKey* aIconKey,
     198                 :   void* aNow)
     199                 : {
     200               0 :   PRTime now = *(reinterpret_cast<PRTime*>(aNow));
     201               0 :   if (now - aIconKey->created >= UNASSOCIATED_ICON_EXPIRY_INTERVAL) {
     202               0 :     return PL_DHASH_REMOVE;
     203                 :   }
     204               0 :   return PL_DHASH_NEXT;
     205                 : }
     206                 : 
     207                 : NS_IMETHODIMP
     208               1 : nsFaviconService::Notify(nsITimer* timer)
     209                 : {
     210               1 :   if (timer != mExpireUnassociatedIconsTimer.get()) {
     211               1 :     return NS_ERROR_INVALID_ARG;
     212                 :   }
     213                 : 
     214               0 :   PRTime now = PR_Now();
     215                 :   mUnassociatedIcons.EnumerateEntries(
     216               0 :     ExpireNonrecentUnassociatedIconsEnumerator, &now);
     217                 :   // Re-init the expiry timer if the cache isn't empty.
     218               0 :   if (mUnassociatedIcons.Count() > 0) {
     219               0 :     mExpireUnassociatedIconsTimer->InitWithCallback(
     220               0 :       this, UNASSOCIATED_ICON_EXPIRY_INTERVAL, nsITimer::TYPE_ONE_SHOT);
     221                 :   }
     222                 : 
     223               0 :   return NS_OK;
     224                 : }
     225                 : 
     226                 : ////////////////////////////////////////////////////////////////////////////////
     227                 : //// nsIFaviconService
     228                 : 
     229                 : NS_IMETHODIMP
     230              90 : nsFaviconService::SetFaviconUrlForPage(nsIURI* aPageURI, nsIURI* aFaviconURI)
     231                 : {
     232              90 :   NS_ENSURE_ARG(aPageURI);
     233              89 :   NS_ENSURE_ARG(aFaviconURI);
     234                 : 
     235                 :   // If we are about to expire all favicons, don't bother setting a new one.
     236              89 :   if (mFaviconsExpirationRunning) {
     237               0 :     return NS_OK;
     238                 :   }
     239                 : 
     240              89 :   nsNavHistory* history = nsNavHistory::GetHistoryService();
     241              89 :   NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
     242                 : 
     243              89 :   if (history->InPrivateBrowsingMode()) {
     244               0 :     return NS_OK;
     245                 :   }
     246                 : 
     247                 :   nsresult rv;
     248              89 :   PRInt64 iconId = -1;
     249              89 :   bool hasData = false;
     250                 :   {
     251                 :     nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
     252                 :       "SELECT id, length(data), expiration FROM moz_favicons "
     253                 :       "WHERE url = :icon_url"
     254             178 :     );
     255              89 :     NS_ENSURE_STATE(stmt);
     256             178 :     mozStorageStatementScoper scoper(stmt);
     257                 : 
     258              89 :     rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
     259              89 :     NS_ENSURE_SUCCESS(rv, rv);
     260                 : 
     261              89 :     bool hasResult = false;
     262              89 :     if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
     263                 :       // We already have an entry for this icon, just get its stats.
     264              84 :       rv = stmt->GetInt64(0, &iconId);
     265              84 :       NS_ENSURE_SUCCESS(rv, rv);
     266                 :       PRInt32 dataSize;
     267              84 :       rv = stmt->GetInt32(1, &dataSize);
     268              84 :       NS_ENSURE_SUCCESS(rv, rv);
     269              84 :       if (dataSize > 0) {
     270              84 :         hasData = true;
     271                 :       }
     272                 :     }
     273                 :   }
     274                 : 
     275             178 :   mozStorageTransaction transaction(mDB->MainConn(), false);
     276                 : 
     277              89 :   if (iconId == -1) {
     278                 :     // We did not find any entry for this icon, so create a new one.
     279                 :     nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
     280                 :       "INSERT INTO moz_favicons (id, url, data, mime_type, expiration, guid) "
     281                 :       "VALUES (:icon_id, :icon_url, :data, :mime_type, :expiration, "
     282                 :               "COALESCE(:guid, GENERATE_GUID()))"
     283              10 :     );
     284               5 :     NS_ENSURE_STATE(stmt);
     285              10 :     mozStorageStatementScoper scoper(stmt);
     286                 : 
     287               5 :     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("guid"));
     288               5 :     NS_ENSURE_SUCCESS(rv, rv);
     289               5 :     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("icon_id"));
     290               5 :     NS_ENSURE_SUCCESS(rv, rv);
     291               5 :     rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
     292               5 :     NS_ENSURE_SUCCESS(rv, rv);
     293               5 :     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("data"));
     294               5 :     NS_ENSURE_SUCCESS(rv, rv);
     295               5 :     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("mime_type"));
     296               5 :     NS_ENSURE_SUCCESS(rv, rv);
     297               5 :     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("expiration"));
     298               5 :     NS_ENSURE_SUCCESS(rv, rv);
     299               5 :     rv = stmt->Execute();
     300               5 :     NS_ENSURE_SUCCESS(rv, rv);
     301                 : 
     302                 :     {
     303                 :       nsCOMPtr<mozIStorageStatement> getInfoStmt = mDB->GetStatement(
     304                 :         "SELECT id, length(data), expiration FROM moz_favicons "
     305                 :         "WHERE url = :icon_url"
     306              10 :       );
     307               5 :       NS_ENSURE_STATE(getInfoStmt);
     308              10 :       mozStorageStatementScoper scoper(getInfoStmt);
     309                 : 
     310               5 :       rv = URIBinder::Bind(getInfoStmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
     311               5 :       NS_ENSURE_SUCCESS(rv, rv);
     312                 :       bool hasResult;
     313               5 :       rv = getInfoStmt->ExecuteStep(&hasResult);
     314               5 :       NS_ENSURE_SUCCESS(rv, rv);
     315               5 :       NS_ASSERTION(hasResult, "hasResult is false but the call succeeded?");
     316              10 :       iconId = getInfoStmt->AsInt64(0);
     317                 :     }
     318                 :   }
     319                 : 
     320                 :   // Now, link our icon entry with the page.
     321                 :   PRInt64 pageId;
     322             178 :   nsCAutoString guid;
     323              89 :   rv = history->GetOrCreateIdForPage(aPageURI, &pageId, guid);
     324              89 :   NS_ENSURE_SUCCESS(rv, rv);
     325                 : 
     326                 :   nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
     327                 :     "UPDATE moz_places SET favicon_id = :icon_id WHERE id = :page_id"
     328             178 :   );
     329              89 :   NS_ENSURE_STATE(stmt);
     330             178 :   mozStorageStatementScoper scoper(stmt);
     331                 : 
     332              89 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), pageId);
     333              89 :   NS_ENSURE_SUCCESS(rv, rv);
     334              89 :   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("icon_id"), iconId);
     335              89 :   NS_ENSURE_SUCCESS(rv, rv);
     336              89 :   rv = stmt->Execute();
     337              89 :   NS_ENSURE_SUCCESS(rv, rv);
     338                 : 
     339              89 :   rv = transaction.Commit();
     340              89 :   NS_ENSURE_SUCCESS(rv, rv);
     341                 : 
     342                 :   // Send favicon change notifications only if the icon has any data.
     343              89 :   if (hasData) {
     344              84 :     SendFaviconNotifications(aPageURI, aFaviconURI, guid);
     345                 :   }
     346                 : 
     347              89 :   return NS_OK;
     348                 : }
     349                 : 
     350                 : 
     351                 : NS_IMETHODIMP
     352             570 : nsFaviconService::GetDefaultFavicon(nsIURI** _retval)
     353                 : {
     354             570 :   NS_ENSURE_ARG_POINTER(_retval);
     355                 : 
     356                 :   // not found, use default
     357             570 :   if (!mDefaultIcon) {
     358              32 :     nsresult rv = NS_NewURI(getter_AddRefs(mDefaultIcon),
     359              64 :                             NS_LITERAL_CSTRING(FAVICON_DEFAULT_URL));
     360              32 :     NS_ENSURE_SUCCESS(rv, rv);
     361                 :   }
     362             570 :   return mDefaultIcon->Clone(_retval);
     363                 : }
     364                 : 
     365                 : void
     366             104 : nsFaviconService::SendFaviconNotifications(nsIURI* aPageURI,
     367                 :                                            nsIURI* aFaviconURI,
     368                 :                                            const nsACString& aGUID)
     369                 : {
     370             208 :   nsCAutoString faviconSpec;
     371             104 :   nsNavHistory* history = nsNavHistory::GetHistoryService();
     372             104 :   if (history && NS_SUCCEEDED(aFaviconURI->GetSpec(faviconSpec))) {
     373                 :     history->SendPageChangedNotification(aPageURI,
     374                 :                                          nsINavHistoryObserver::ATTRIBUTE_FAVICON,
     375             104 :                                          NS_ConvertUTF8toUTF16(faviconSpec),
     376             104 :                                          aGUID);
     377                 :   }
     378             104 : }
     379                 : 
     380                 : 
     381                 : NS_IMETHODIMP
     382              28 : nsFaviconService::SetAndLoadFaviconForPage(nsIURI* aPageURI,
     383                 :                                            nsIURI* aFaviconURI,
     384                 :                                            bool aForceReload,
     385                 :                                            nsIFaviconDataCallback* aCallback)
     386                 : {
     387              28 :   NS_ENSURE_ARG(aPageURI);
     388              25 :   NS_ENSURE_ARG(aFaviconURI);
     389                 : 
     390              24 :   if (mFaviconsExpirationRunning)
     391               0 :     return NS_OK;
     392                 : 
     393                 :   // If a favicon is in the failed cache, only load it during a forced reload.
     394                 :   bool previouslyFailed;
     395              24 :   nsresult rv = IsFailedFavicon(aFaviconURI, &previouslyFailed);
     396              24 :   NS_ENSURE_SUCCESS(rv, rv);
     397              24 :   if (previouslyFailed) {
     398               0 :     if (aForceReload)
     399               0 :       RemoveFailedFavicon(aFaviconURI);
     400                 :     else
     401               0 :       return NS_OK;
     402                 :   }
     403                 : 
     404                 :   // Check if the icon already exists and fetch it from the network, if needed.
     405                 :   // Finally associate the icon to the requested page if not yet associated.
     406                 :   rv = AsyncFetchAndSetIconForPage::start(
     407                 :     aFaviconURI, aPageURI, aForceReload ? FETCH_ALWAYS : FETCH_IF_MISSING,
     408                 :     aCallback
     409              24 :   );
     410              24 :   NS_ENSURE_SUCCESS(rv, rv);
     411                 : 
     412                 :   // DB will be updated and observers notified when data has finished loading.
     413              24 :   return NS_OK;
     414                 : }
     415                 : 
     416                 : NS_IMETHODIMP
     417              15 : nsFaviconService::SetAndFetchFaviconForPage(nsIURI* aPageURI,
     418                 :                                             nsIURI* aFaviconURI,
     419                 :                                             bool aForceReload,
     420                 :                                             nsIFaviconDataCallback* aCallback)
     421                 : {
     422                 :   return SetAndLoadFaviconForPage(aPageURI, aFaviconURI,
     423              15 :                                   aForceReload, aCallback);
     424                 : }
     425                 : 
     426                 : NS_IMETHODIMP
     427              20 : nsFaviconService::ReplaceFaviconData(nsIURI* aFaviconURI,
     428                 :                                     const PRUint8* aData,
     429                 :                                     PRUint32 aDataLen,
     430                 :                                     const nsACString& aMimeType,
     431                 :                                     PRTime aExpiration)
     432                 : {
     433              20 :   NS_ENSURE_ARG(aFaviconURI);
     434              18 :   NS_ENSURE_ARG(aData);
     435              17 :   NS_ENSURE_TRUE(aDataLen > 0, NS_ERROR_INVALID_ARG);
     436              17 :   NS_ENSURE_TRUE(aMimeType.Length() > 0, NS_ERROR_INVALID_ARG);
     437              16 :   if (aExpiration == 0) {
     438               8 :     aExpiration = PR_Now() + MAX_FAVICON_EXPIRATION;
     439                 :   }
     440                 : 
     441              16 :   if (mFaviconsExpirationRunning)
     442               0 :     return NS_OK;
     443                 : 
     444              16 :   UnassociatedIconHashKey* iconKey = mUnassociatedIcons.PutEntry(aFaviconURI);
     445              16 :   if (!iconKey) {
     446               0 :     return NS_ERROR_OUT_OF_MEMORY;
     447                 :   }
     448                 : 
     449              16 :   iconKey->created = PR_Now();
     450                 : 
     451                 :   // If the cache contains unassociated icons, an expiry timer should already exist, otherwise
     452                 :   // there may be a timer left hanging around, so make sure we fire a new one.
     453              16 :   PRInt32 unassociatedCount = mUnassociatedIcons.Count();
     454              16 :   if (unassociatedCount == 1) {
     455               8 :     mExpireUnassociatedIconsTimer->Cancel();
     456               8 :     mExpireUnassociatedIconsTimer->InitWithCallback(
     457               8 :       this, UNASSOCIATED_ICON_EXPIRY_INTERVAL, nsITimer::TYPE_ONE_SHOT);
     458                 :   }
     459                 : 
     460              16 :   IconData* iconData = &(iconKey->iconData);
     461              16 :   iconData->expiration = aExpiration;
     462              16 :   iconData->status = ICON_STATUS_CACHED;
     463              16 :   iconData->fetchMode = FETCH_NEVER;
     464              16 :   nsresult rv = aFaviconURI->GetSpec(iconData->spec);
     465              16 :   NS_ENSURE_SUCCESS(rv, rv);
     466                 : 
     467                 :   // If the page provided a large image for the favicon (eg, a highres image
     468                 :   // or a multiresolution .ico file), we don't want to store more data than
     469                 :   // needed.
     470              16 :   if (aDataLen > MAX_ICON_FILESIZE(mOptimizedIconDimension)) {
     471               0 :     rv = OptimizeFaviconImage(aData, aDataLen, aMimeType, iconData->data, iconData->mimeType);
     472               0 :     NS_ENSURE_SUCCESS(rv, rv);
     473                 : 
     474               0 :     if (iconData->data.Length() > MAX_FAVICON_SIZE) {
     475                 :       // We cannot optimize this favicon size and we are over the maximum size
     476                 :       // allowed, so we will not save data to the db to avoid bloating it.
     477               0 :       mUnassociatedIcons.RemoveEntry(aFaviconURI);
     478               0 :       return NS_ERROR_FAILURE;
     479                 :     }
     480                 :   } else {
     481              16 :     iconData->mimeType.Assign(aMimeType);
     482              16 :     iconData->data.Assign(TO_CHARBUFFER(aData), aDataLen);
     483                 :   }
     484                 : 
     485                 :   // If the database contains an icon at the given url, we will update the
     486                 :   // database immediately so that the associated pages are kept in sync.
     487                 :   // Otherwise, do nothing and let the icon be picked up from the memory hash.
     488              16 :   rv = AsyncReplaceFaviconData::start(iconData);
     489              16 :   NS_ENSURE_SUCCESS(rv, rv);
     490                 : 
     491              16 :   return NS_OK;
     492                 : }
     493                 : 
     494                 : // nsFaviconService::SetFaviconData
     495                 : //
     496                 : //    See the IDL for this function for lots of info. Note from there: we don't
     497                 : //    send out notifications.
     498                 : 
     499                 : NS_IMETHODIMP
     500             104 : nsFaviconService::SetFaviconData(nsIURI* aFaviconURI, const PRUint8* aData,
     501                 :                                  PRUint32 aDataLen, const nsACString& aMimeType,
     502                 :                                  PRTime aExpiration)
     503                 : {
     504             104 :   NS_ENSURE_ARG(aFaviconURI);
     505                 : 
     506             103 :   if (mFaviconsExpirationRunning)
     507               0 :     return NS_OK;
     508                 : 
     509                 :   nsresult rv;
     510             103 :   PRUint32 dataLen = aDataLen;
     511             103 :   const PRUint8* data = aData;
     512             103 :   const nsACString* mimeType = &aMimeType;
     513             206 :   nsCString newData, newMimeType;
     514                 : 
     515                 :   // If the page provided a large image for the favicon (eg, a highres image
     516                 :   // or a multiresolution .ico file), we don't want to store more data than
     517                 :   // needed.
     518             103 :   if (aDataLen > MAX_ICON_FILESIZE(mOptimizedIconDimension)) {
     519               7 :     rv = OptimizeFaviconImage(aData, aDataLen, aMimeType, newData, newMimeType);
     520               7 :     if (NS_SUCCEEDED(rv) && newData.Length() < aDataLen) {
     521               7 :       data = reinterpret_cast<PRUint8*>(const_cast<char*>(newData.get())),
     522               7 :       dataLen = newData.Length();
     523               7 :       mimeType = &newMimeType;
     524                 :     }
     525               0 :     else if (aDataLen > MAX_FAVICON_SIZE) {
     526                 :       // We cannot optimize this favicon size and we are over the maximum size
     527                 :       // allowed, so we will not save data to the db to avoid bloating it.
     528               0 :       return NS_ERROR_FAILURE;
     529                 :     }
     530                 :   }
     531                 : 
     532             206 :   nsCOMPtr<mozIStorageStatement> statement;
     533                 :   {
     534                 :     // this block forces the scoper to reset our statement: necessary for the
     535                 :     // next statement
     536                 :     nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
     537                 :       "SELECT id, length(data), expiration FROM moz_favicons "
     538                 :       "WHERE url = :icon_url"
     539             206 :     );
     540             103 :     NS_ENSURE_STATE(stmt);
     541             206 :     mozStorageStatementScoper scoper(stmt);
     542                 : 
     543             103 :     rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
     544             103 :     NS_ENSURE_SUCCESS(rv, rv);
     545                 : 
     546                 :     bool hasResult;
     547             103 :     rv = stmt->ExecuteStep(&hasResult);
     548             103 :     NS_ENSURE_SUCCESS(rv, rv);
     549                 : 
     550             103 :     if (hasResult) {
     551                 :       // Get id of the old entry and update it.
     552                 :       PRInt64 id;
     553              45 :       rv = stmt->GetInt64(0, &id);
     554              45 :       NS_ENSURE_SUCCESS(rv, rv);
     555                 :       statement = mDB->GetStatement(
     556                 :         "UPDATE moz_favicons SET "
     557                 :                "guid       = COALESCE(:guid, guid), "
     558                 :                "data       = :data, "
     559                 :                "mime_type  = :mime_type, "
     560                 :                "expiration = :expiration "
     561                 :         "WHERE id = :icon_id"
     562              45 :       );
     563              45 :       NS_ENSURE_STATE(statement);
     564                 : 
     565              45 :       rv = statement->BindNullByName(NS_LITERAL_CSTRING("guid"));
     566              45 :       NS_ENSURE_SUCCESS(rv, rv);
     567              45 :       rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("icon_id"), id);
     568              45 :       NS_ENSURE_SUCCESS(rv, rv);
     569              45 :       rv = statement->BindBlobByName(NS_LITERAL_CSTRING("data"), data, dataLen);
     570              45 :       NS_ENSURE_SUCCESS(rv, rv);
     571              45 :       rv = statement->BindUTF8StringByName(NS_LITERAL_CSTRING("mime_type"), *mimeType);
     572              45 :       NS_ENSURE_SUCCESS(rv, rv);
     573              45 :       rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("expiration"), aExpiration);
     574              45 :       NS_ENSURE_SUCCESS(rv, rv);
     575                 :     }
     576                 :     else {
     577                 :       // Insert a new entry.
     578                 :       statement = mDB->GetStatement(
     579                 :        "INSERT INTO moz_favicons (id, url, data, mime_type, expiration, guid) "
     580                 :        "VALUES (:icon_id, :icon_url, :data, :mime_type, :expiration, "
     581              58 :                "COALESCE(:guid, GENERATE_GUID()))");
     582              58 :       NS_ENSURE_STATE(statement);
     583                 : 
     584              58 :       rv = statement->BindNullByName(NS_LITERAL_CSTRING("icon_id"));
     585              58 :       NS_ENSURE_SUCCESS(rv, rv);
     586              58 :       rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
     587              58 :       NS_ENSURE_SUCCESS(rv, rv);
     588              58 :       rv = statement->BindBlobByName(NS_LITERAL_CSTRING("data"), data, dataLen);
     589              58 :       NS_ENSURE_SUCCESS(rv, rv);
     590              58 :       rv = statement->BindUTF8StringByName(NS_LITERAL_CSTRING("mime_type"), *mimeType);
     591              58 :       NS_ENSURE_SUCCESS(rv, rv);
     592              58 :       rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("expiration"), aExpiration);
     593              58 :       NS_ENSURE_SUCCESS(rv, rv);
     594              58 :       rv = statement->BindNullByName(NS_LITERAL_CSTRING("guid"));
     595              58 :       NS_ENSURE_SUCCESS(rv, rv);
     596                 :     }
     597                 :   }
     598             206 :   mozStorageStatementScoper statementScoper(statement);
     599                 : 
     600             103 :   rv = statement->Execute();
     601             103 :   NS_ENSURE_SUCCESS(rv, rv);
     602                 : 
     603             103 :   return NS_OK;
     604                 : }
     605                 : 
     606                 : NS_IMETHODIMP
     607              11 : nsFaviconService::ReplaceFaviconDataFromDataURL(nsIURI* aFaviconURI,
     608                 :                                                const nsAString& aDataURL,
     609                 :                                                PRTime aExpiration)
     610                 : {
     611              11 :   NS_ENSURE_ARG(aFaviconURI);
     612               9 :   NS_ENSURE_TRUE(aDataURL.Length() > 0, NS_ERROR_INVALID_ARG);
     613               8 :   if (aExpiration == 0) {
     614               8 :     aExpiration = PR_Now() + MAX_FAVICON_EXPIRATION;
     615                 :   }
     616                 : 
     617               8 :   if (mFaviconsExpirationRunning)
     618               0 :     return NS_OK;
     619                 : 
     620              16 :   nsCOMPtr<nsIURI> dataURI;
     621               8 :   nsresult rv = NS_NewURI(getter_AddRefs(dataURI), aDataURL);
     622               8 :   NS_ENSURE_SUCCESS(rv, rv);
     623                 : 
     624                 :   // Use the data: protocol handler to convert the data.
     625              16 :   nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
     626               8 :   NS_ENSURE_SUCCESS(rv, rv);
     627              16 :   nsCOMPtr<nsIProtocolHandler> protocolHandler;
     628               8 :   rv = ioService->GetProtocolHandler("data", getter_AddRefs(protocolHandler));
     629               8 :   NS_ENSURE_SUCCESS(rv, rv);
     630                 : 
     631              16 :   nsCOMPtr<nsIChannel> channel;
     632               8 :   rv = protocolHandler->NewChannel(dataURI, getter_AddRefs(channel));
     633               8 :   NS_ENSURE_SUCCESS(rv, rv);
     634                 : 
     635                 :   // Blocking stream is OK for data URIs.
     636              16 :   nsCOMPtr<nsIInputStream> stream;
     637               8 :   rv = channel->Open(getter_AddRefs(stream));
     638               8 :   NS_ENSURE_SUCCESS(rv, rv);
     639                 : 
     640                 :   PRUint32 available;
     641               8 :   rv = stream->Available(&available);
     642               8 :   NS_ENSURE_SUCCESS(rv, rv);
     643               8 :   if (available == 0)
     644               0 :     return NS_ERROR_FAILURE;
     645                 : 
     646                 :   // Read all the decoded data.
     647                 :   PRUint8* buffer = static_cast<PRUint8*>
     648               8 :                                (nsMemory::Alloc(sizeof(PRUint8) * available));
     649               8 :   if (!buffer)
     650               0 :     return NS_ERROR_OUT_OF_MEMORY;
     651                 :   PRUint32 numRead;
     652               8 :   rv = stream->Read(TO_CHARBUFFER(buffer), available, &numRead);
     653               8 :   if (NS_FAILED(rv) || numRead != available) {
     654               0 :     nsMemory::Free(buffer);
     655               0 :     return rv;
     656                 :   }
     657                 : 
     658              16 :   nsCAutoString mimeType;
     659               8 :   rv = channel->GetContentType(mimeType);
     660               8 :   if (NS_FAILED(rv)) {
     661               0 :     nsMemory::Free(buffer);
     662               0 :     return rv;
     663                 :   }
     664                 : 
     665                 :   // ReplaceFaviconData can now do the dirty work.
     666               8 :   rv = ReplaceFaviconData(aFaviconURI, buffer, available, mimeType, aExpiration);
     667               8 :   nsMemory::Free(buffer);
     668               8 :   NS_ENSURE_SUCCESS(rv, rv);
     669                 : 
     670               8 :   return NS_OK;
     671                 : }
     672                 : 
     673                 : NS_IMETHODIMP
     674              91 : nsFaviconService::SetFaviconDataFromDataURL(nsIURI* aFaviconURI,
     675                 :                                             const nsAString& aDataURL,
     676                 :                                             PRTime aExpiration)
     677                 : {
     678              91 :   NS_ENSURE_ARG(aFaviconURI);
     679              90 :   if (mFaviconsExpirationRunning)
     680               0 :     return NS_OK;
     681                 : 
     682             180 :   nsCOMPtr<nsIURI> dataURI;
     683              90 :   nsresult rv = NS_NewURI(getter_AddRefs(dataURI), aDataURL);
     684              90 :   NS_ENSURE_SUCCESS(rv, rv);
     685                 : 
     686                 :   // use the data: protocol handler to convert the data
     687             178 :   nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
     688              89 :   NS_ENSURE_SUCCESS(rv, rv);
     689             178 :   nsCOMPtr<nsIProtocolHandler> protocolHandler;
     690              89 :   rv = ioService->GetProtocolHandler("data", getter_AddRefs(protocolHandler));
     691              89 :   NS_ENSURE_SUCCESS(rv, rv);
     692                 : 
     693             178 :   nsCOMPtr<nsIChannel> channel;
     694              89 :   rv = protocolHandler->NewChannel(dataURI, getter_AddRefs(channel));
     695              89 :   NS_ENSURE_SUCCESS(rv, rv);
     696                 : 
     697                 :   // blocking stream is OK for data URIs
     698             178 :   nsCOMPtr<nsIInputStream> stream;
     699              89 :   rv = channel->Open(getter_AddRefs(stream));
     700              89 :   NS_ENSURE_SUCCESS(rv, rv);
     701                 : 
     702                 :   PRUint32 available;
     703              89 :   rv = stream->Available(&available);
     704              89 :   NS_ENSURE_SUCCESS(rv, rv);
     705              89 :   if (available == 0)
     706               0 :     return NS_ERROR_FAILURE;
     707                 : 
     708                 :   // read all the decoded data
     709                 :   PRUint8* buffer = static_cast<PRUint8*>
     710              89 :                                (nsMemory::Alloc(sizeof(PRUint8) * available));
     711              89 :   if (!buffer)
     712               0 :     return NS_ERROR_OUT_OF_MEMORY;
     713                 :   PRUint32 numRead;
     714              89 :   rv = stream->Read(reinterpret_cast<char*>(buffer), available, &numRead);
     715              89 :   if (NS_FAILED(rv) || numRead != available) {
     716               0 :     nsMemory::Free(buffer);
     717               0 :     return rv;
     718                 :   }
     719                 : 
     720             178 :   nsCAutoString mimeType;
     721              89 :   rv = channel->GetContentType(mimeType);
     722              89 :   NS_ENSURE_SUCCESS(rv, rv);
     723                 : 
     724                 :   // SetFaviconData can now do the dirty work.
     725              89 :   rv = SetFaviconData(aFaviconURI, buffer, available, mimeType, aExpiration);
     726              89 :   nsMemory::Free(buffer);
     727              89 :   NS_ENSURE_SUCCESS(rv, rv);
     728                 : 
     729              89 :   return NS_OK;
     730                 : }
     731                 : 
     732                 : 
     733                 : NS_IMETHODIMP
     734              99 : nsFaviconService::GetFaviconData(nsIURI* aFaviconURI, nsACString& aMimeType,
     735                 :                                  PRUint32* aDataLen, PRUint8** aData)
     736                 : {
     737              99 :   NS_ENSURE_ARG(aFaviconURI);
     738              98 :   NS_ENSURE_ARG_POINTER(aDataLen);
     739              98 :   NS_ENSURE_ARG_POINTER(aData);
     740                 : 
     741             196 :   nsCOMPtr<nsIURI> defaultFaviconURI;
     742              98 :   nsresult rv = GetDefaultFavicon(getter_AddRefs(defaultFaviconURI));
     743              98 :   NS_ENSURE_SUCCESS(rv, rv);
     744                 : 
     745              98 :   bool isDefaultFavicon = false;
     746              98 :   rv = defaultFaviconURI->Equals(aFaviconURI, &isDefaultFavicon);
     747              98 :   NS_ENSURE_SUCCESS(rv, rv);
     748                 : 
     749                 :   // If we're getting the default favicon, we need to handle it separately since
     750                 :   // it's not in the database.
     751              98 :   if (isDefaultFavicon) {
     752               2 :     nsCAutoString defaultData;
     753               1 :     rv = GetDefaultFaviconData(defaultData);
     754               1 :     NS_ENSURE_SUCCESS(rv, rv);
     755                 : 
     756               1 :     PRUint8* bytes = reinterpret_cast<PRUint8*>(ToNewCString(defaultData));
     757               1 :     NS_ENSURE_STATE(bytes);
     758                 : 
     759               1 :     *aData = bytes;
     760               1 :     *aDataLen = defaultData.Length();
     761               1 :     aMimeType.AssignLiteral(DEFAULT_MIME_TYPE);
     762                 : 
     763               1 :     return NS_OK;
     764                 :   }
     765                 : 
     766                 :   nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
     767                 :     "SELECT f.data, f.mime_type FROM moz_favicons f WHERE url = :icon_url"
     768             194 :   );
     769              97 :   NS_ENSURE_STATE(stmt);
     770             194 :   mozStorageStatementScoper scoper(stmt);
     771                 : 
     772              97 :   rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
     773              97 :   NS_ENSURE_SUCCESS(rv, rv);
     774                 : 
     775              97 :   bool hasResult = false;
     776              97 :   if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
     777              97 :     rv = stmt->GetUTF8String(1, aMimeType);
     778              97 :     NS_ENSURE_SUCCESS(rv, rv);
     779                 : 
     780              97 :     return stmt->GetBlob(0, aDataLen, aData);
     781                 :   }
     782               0 :   return NS_ERROR_NOT_AVAILABLE;
     783                 : }
     784                 : 
     785                 : 
     786                 : nsresult
     787               1 : nsFaviconService::GetDefaultFaviconData(nsCString& byteStr)
     788                 : {
     789               1 :   if (mDefaultFaviconData.IsEmpty()) {
     790               2 :     nsCOMPtr<nsIURI> defaultFaviconURI;
     791               1 :     nsresult rv = GetDefaultFavicon(getter_AddRefs(defaultFaviconURI));
     792               1 :     NS_ENSURE_SUCCESS(rv, rv);
     793                 : 
     794               2 :     nsCOMPtr<nsIInputStream> istream;
     795               1 :     rv = NS_OpenURI(getter_AddRefs(istream), defaultFaviconURI);
     796               1 :     NS_ENSURE_SUCCESS(rv, rv);
     797                 : 
     798               1 :     rv = NS_ConsumeStream(istream, PR_UINT32_MAX, mDefaultFaviconData);
     799               1 :     NS_ENSURE_SUCCESS(rv, rv);
     800                 : 
     801               1 :     rv = istream->Close();
     802               1 :     NS_ENSURE_SUCCESS(rv, rv);
     803                 : 
     804               1 :     if (mDefaultFaviconData.IsEmpty())
     805               0 :       return NS_ERROR_UNEXPECTED;
     806                 :   }
     807                 : 
     808               1 :   byteStr.Assign(mDefaultFaviconData);
     809               1 :   return NS_OK;
     810                 : }
     811                 : 
     812                 : 
     813                 : NS_IMETHODIMP
     814              68 : nsFaviconService::GetFaviconDataAsDataURL(nsIURI* aFaviconURI,
     815                 :                                           nsAString& aDataURL)
     816                 : {
     817              68 :   NS_ENSURE_ARG(aFaviconURI);
     818                 : 
     819                 :   PRUint8* data;
     820                 :   PRUint32 dataLen;
     821             134 :   nsCAutoString mimeType;
     822                 : 
     823              67 :   nsresult rv = GetFaviconData(aFaviconURI, mimeType, &dataLen, &data);
     824              67 :   NS_ENSURE_SUCCESS(rv, rv);
     825                 : 
     826              67 :   if (!data) {
     827               1 :     aDataURL.SetIsVoid(true);
     828               1 :     return NS_OK;
     829                 :   }
     830                 : 
     831                 :   char* encoded = PL_Base64Encode(reinterpret_cast<const char*>(data),
     832              66 :                                   dataLen, nsnull);
     833              66 :   nsMemory::Free(data);
     834                 : 
     835              66 :   if (!encoded)
     836               0 :     return NS_ERROR_OUT_OF_MEMORY;
     837                 : 
     838              66 :   aDataURL.AssignLiteral("data:");
     839              66 :   AppendUTF8toUTF16(mimeType, aDataURL);
     840              66 :   aDataURL.AppendLiteral(";base64,");
     841              66 :   AppendUTF8toUTF16(encoded, aDataURL);
     842                 : 
     843              66 :   nsMemory::Free(encoded);
     844              66 :   return NS_OK;
     845                 : }
     846                 : 
     847                 : 
     848                 : NS_IMETHODIMP
     849             118 : nsFaviconService::GetFaviconForPage(nsIURI* aPageURI, nsIURI** _retval)
     850                 : {
     851             118 :   NS_ENSURE_ARG(aPageURI);
     852             117 :   NS_ENSURE_ARG_POINTER(_retval);
     853                 : 
     854                 :   nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
     855                 :     "SELECT f.id, f.url, length(f.data), f.expiration "
     856                 :     "FROM moz_places h "
     857                 :     "JOIN moz_favicons f ON h.favicon_id = f.id "
     858                 :     "WHERE h.url = :page_url "
     859                 :     "LIMIT 1"
     860             234 :   );
     861             117 :   NS_ENSURE_STATE(stmt);
     862             234 :   mozStorageStatementScoper scoper(stmt);
     863                 : 
     864             117 :   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aPageURI);
     865             117 :   NS_ENSURE_SUCCESS(rv, rv);
     866                 : 
     867                 :   bool hasResult;
     868             117 :   if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
     869             166 :     nsCAutoString url;
     870              83 :     rv = stmt->GetUTF8String(1, url);
     871              83 :     NS_ENSURE_SUCCESS(rv, rv);
     872                 : 
     873              83 :     return NS_NewURI(_retval, url);
     874                 :   }
     875              34 :   return NS_ERROR_NOT_AVAILABLE;
     876                 : }
     877                 : 
     878                 : 
     879                 : NS_IMETHODIMP
     880               2 : nsFaviconService::GetFaviconURLForPage(nsIURI *aPageURI,
     881                 :                                        nsIFaviconDataCallback* aCallback)
     882                 : {
     883               2 :   NS_ENSURE_ARG(aPageURI);
     884               1 :   NS_ENSURE_ARG(aCallback);
     885                 : 
     886               1 :   nsresult rv = AsyncGetFaviconURLForPage::start(aPageURI, aCallback);
     887               1 :   NS_ENSURE_SUCCESS(rv, rv);
     888               1 :   return NS_OK;
     889                 : }
     890                 : 
     891                 : NS_IMETHODIMP
     892               2 : nsFaviconService::GetFaviconDataForPage(nsIURI* aPageURI,
     893                 :                                         nsIFaviconDataCallback* aCallback)
     894                 : {
     895               2 :   NS_ENSURE_ARG(aPageURI);
     896               1 :   NS_ENSURE_ARG(aCallback);
     897                 : 
     898               1 :   nsresult rv = AsyncGetFaviconDataForPage::start(aPageURI, aCallback);
     899               1 :   NS_ENSURE_SUCCESS(rv, rv);
     900               1 :   return NS_OK;
     901                 : }
     902                 : 
     903                 : NS_IMETHODIMP
     904               2 : nsFaviconService::GetFaviconImageForPage(nsIURI* aPageURI, nsIURI** _retval)
     905                 : {
     906               2 :   NS_ENSURE_ARG(aPageURI);
     907               1 :   NS_ENSURE_ARG_POINTER(_retval);
     908                 : 
     909                 :   nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
     910                 :     "SELECT f.id, f.url, length(f.data), f.expiration "
     911                 :     "FROM moz_places h "
     912                 :     "JOIN moz_favicons f ON h.favicon_id = f.id "
     913                 :     "WHERE h.url = :page_url "
     914                 :     "LIMIT 1"
     915               2 :   );
     916               1 :   NS_ENSURE_STATE(stmt);
     917               2 :   mozStorageStatementScoper scoper(stmt);
     918                 : 
     919               1 :   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aPageURI);
     920               1 :   NS_ENSURE_SUCCESS(rv, rv);
     921                 : 
     922                 :   bool hasResult;
     923               2 :   nsCOMPtr<nsIURI> faviconURI;
     924               1 :   if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
     925                 :     PRInt32 dataLen;
     926               1 :     rv = stmt->GetInt32(2, &dataLen);
     927               1 :     NS_ENSURE_SUCCESS(rv, rv);
     928               1 :     if (dataLen > 0) {
     929                 :       // this page has a favicon entry with data
     930               2 :       nsCAutoString favIconUri;
     931               1 :       rv = stmt->GetUTF8String(1, favIconUri);
     932               1 :       NS_ENSURE_SUCCESS(rv, rv);
     933                 : 
     934               1 :       return GetFaviconLinkForIconString(favIconUri, _retval);
     935                 :     }
     936                 :   }
     937                 : 
     938                 :   // not found, use default
     939               0 :   return GetDefaultFavicon(_retval);
     940                 : }
     941                 : 
     942                 : 
     943                 : nsresult
     944               5 : nsFaviconService::GetFaviconLinkForIcon(nsIURI* aFaviconURI,
     945                 :                                         nsIURI** aOutputURI)
     946                 : {
     947               5 :   NS_ENSURE_ARG(aFaviconURI);
     948               2 :   NS_ENSURE_ARG_POINTER(aOutputURI);
     949                 : 
     950               4 :   nsCAutoString spec;
     951               2 :   if (aFaviconURI) {
     952               2 :     nsresult rv = aFaviconURI->GetSpec(spec);
     953               2 :     NS_ENSURE_SUCCESS(rv, rv);
     954                 :   }
     955               2 :   return GetFaviconLinkForIconString(spec, aOutputURI);
     956                 : }
     957                 : 
     958                 : 
     959                 : static PLDHashOperator
     960               0 : ExpireFailedFaviconsCallback(nsCStringHashKey::KeyType aKey,
     961                 :                              PRUint32& aData,
     962                 :                              void* userArg)
     963                 : {
     964               0 :   PRUint32* threshold = reinterpret_cast<PRUint32*>(userArg);
     965               0 :   if (aData < *threshold)
     966               0 :     return PL_DHASH_REMOVE;
     967               0 :   return PL_DHASH_NEXT;
     968                 : }
     969                 : 
     970                 : 
     971                 : NS_IMETHODIMP
     972               2 : nsFaviconService::AddFailedFavicon(nsIURI* aFaviconURI)
     973                 : {
     974               2 :   NS_ENSURE_ARG(aFaviconURI);
     975                 : 
     976               2 :   nsCAutoString spec;
     977               1 :   nsresult rv = aFaviconURI->GetSpec(spec);
     978               1 :   NS_ENSURE_SUCCESS(rv, rv);
     979                 : 
     980               1 :   if (! mFailedFavicons.Put(spec, mFailedFaviconSerial))
     981               0 :     return NS_ERROR_OUT_OF_MEMORY;
     982               1 :   mFailedFaviconSerial ++;
     983                 : 
     984               1 :   if (mFailedFavicons.Count() > MAX_FAVICON_CACHE_SIZE) {
     985                 :     // need to expire some entries, delete the FAVICON_CACHE_REDUCE_COUNT number
     986                 :     // of items that are the oldest
     987                 :     PRUint32 threshold = mFailedFaviconSerial -
     988               0 :                          MAX_FAVICON_CACHE_SIZE + FAVICON_CACHE_REDUCE_COUNT;
     989               0 :     mFailedFavicons.Enumerate(ExpireFailedFaviconsCallback, &threshold);
     990                 :   }
     991               1 :   return NS_OK;
     992                 : }
     993                 : 
     994                 : 
     995                 : NS_IMETHODIMP
     996               2 : nsFaviconService::RemoveFailedFavicon(nsIURI* aFaviconURI)
     997                 : {
     998               2 :   NS_ENSURE_ARG(aFaviconURI);
     999                 : 
    1000               2 :   nsCAutoString spec;
    1001               1 :   nsresult rv = aFaviconURI->GetSpec(spec);
    1002               1 :   NS_ENSURE_SUCCESS(rv, rv);
    1003                 : 
    1004                 :   // we silently do nothing and succeed if the icon is not in the cache
    1005               1 :   mFailedFavicons.Remove(spec);
    1006               1 :   return NS_OK;
    1007                 : }
    1008                 : 
    1009                 : 
    1010                 : NS_IMETHODIMP
    1011              27 : nsFaviconService::IsFailedFavicon(nsIURI* aFaviconURI, bool* _retval)
    1012                 : {
    1013              27 :   NS_ENSURE_ARG(aFaviconURI);
    1014              52 :   nsCAutoString spec;
    1015              26 :   nsresult rv = aFaviconURI->GetSpec(spec);
    1016              26 :   NS_ENSURE_SUCCESS(rv, rv);
    1017                 : 
    1018                 :   PRUint32 serial;
    1019              26 :   *_retval = mFailedFavicons.Get(spec, &serial);
    1020              26 :   return NS_OK;
    1021                 : }
    1022                 : 
    1023                 : 
    1024                 : // nsFaviconService::GetFaviconLinkForIconString
    1025                 : //
    1026                 : //    This computes a favicon URL with string input and using the cached
    1027                 : //    default one to minimize parsing.
    1028                 : 
    1029                 : nsresult
    1030               3 : nsFaviconService::GetFaviconLinkForIconString(const nsCString& aSpec,
    1031                 :                                               nsIURI** aOutput)
    1032                 : {
    1033               3 :   if (aSpec.IsEmpty()) {
    1034                 :     // default icon for empty strings
    1035               0 :     if (! mDefaultIcon) {
    1036               0 :       nsresult rv = NS_NewURI(getter_AddRefs(mDefaultIcon),
    1037               0 :                               NS_LITERAL_CSTRING(FAVICON_DEFAULT_URL));
    1038               0 :       NS_ENSURE_SUCCESS(rv, rv);
    1039                 :     }
    1040               0 :     return mDefaultIcon->Clone(aOutput);
    1041                 :   }
    1042                 : 
    1043               3 :   if (StringBeginsWith(aSpec, NS_LITERAL_CSTRING("chrome:"))) {
    1044                 :     // pass through for chrome URLs, since they can be referenced without
    1045                 :     // this service
    1046               0 :     return NS_NewURI(aOutput, aSpec);
    1047                 :   }
    1048                 : 
    1049               6 :   nsCAutoString annoUri;
    1050               3 :   annoUri.AssignLiteral("moz-anno:" FAVICON_ANNOTATION_NAME ":");
    1051               3 :   annoUri += aSpec;
    1052               3 :   return NS_NewURI(aOutput, annoUri);
    1053                 : }
    1054                 : 
    1055                 : 
    1056                 : // nsFaviconService::GetFaviconSpecForIconString
    1057                 : //
    1058                 : //    This computes a favicon spec for when you don't want a URI object (as in
    1059                 : //    the tree view implementation), sparing all parsing and normalization.
    1060                 : void
    1061               0 : nsFaviconService::GetFaviconSpecForIconString(const nsCString& aSpec,
    1062                 :                                               nsACString& aOutput)
    1063                 : {
    1064               0 :   if (aSpec.IsEmpty()) {
    1065               0 :     aOutput.AssignLiteral(FAVICON_DEFAULT_URL);
    1066               0 :   } else if (StringBeginsWith(aSpec, NS_LITERAL_CSTRING("chrome:"))) {
    1067               0 :     aOutput = aSpec;
    1068                 :   } else {
    1069               0 :     aOutput.AssignLiteral("moz-anno:" FAVICON_ANNOTATION_NAME ":");
    1070               0 :     aOutput += aSpec;
    1071                 :   }
    1072               0 : }
    1073                 : 
    1074                 : 
    1075                 : // nsFaviconService::OptimizeFaviconImage
    1076                 : //
    1077                 : // Given a blob of data (a image file already read into a buffer), optimize
    1078                 : // its size by recompressing it as a 16x16 PNG.
    1079                 : nsresult
    1080               7 : nsFaviconService::OptimizeFaviconImage(const PRUint8* aData, PRUint32 aDataLen,
    1081                 :                                        const nsACString& aMimeType,
    1082                 :                                        nsACString& aNewData,
    1083                 :                                        nsACString& aNewMimeType)
    1084                 : {
    1085                 :   nsresult rv;
    1086                 : 
    1087              14 :   nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1");
    1088                 : 
    1089              14 :   nsCOMPtr<nsIInputStream> stream;
    1090               7 :   rv = NS_NewByteInputStream(getter_AddRefs(stream),
    1091                 :                 reinterpret_cast<const char*>(aData), aDataLen,
    1092               7 :                 NS_ASSIGNMENT_DEPEND);
    1093               7 :   NS_ENSURE_SUCCESS(rv, rv);
    1094                 : 
    1095                 :   // decode image
    1096              14 :   nsCOMPtr<imgIContainer> container;
    1097               7 :   rv = imgtool->DecodeImageData(stream, aMimeType, getter_AddRefs(container));
    1098               7 :   NS_ENSURE_SUCCESS(rv, rv);
    1099                 : 
    1100               7 :   aNewMimeType.AssignLiteral(DEFAULT_MIME_TYPE);
    1101                 : 
    1102                 :   // scale and recompress
    1103              14 :   nsCOMPtr<nsIInputStream> iconStream;
    1104               7 :   rv = imgtool->EncodeScaledImage(container, aNewMimeType,
    1105                 :                                   mOptimizedIconDimension,
    1106                 :                                   mOptimizedIconDimension,
    1107               7 :                                   EmptyString(),
    1108              14 :                                   getter_AddRefs(iconStream));
    1109               7 :   NS_ENSURE_SUCCESS(rv, rv);
    1110                 : 
    1111                 :   // Read the stream into a new buffer.
    1112               7 :   rv = NS_ConsumeStream(iconStream, PR_UINT32_MAX, aNewData);
    1113               7 :   NS_ENSURE_SUCCESS(rv, rv);
    1114                 : 
    1115               7 :   return NS_OK;
    1116                 : }
    1117                 : 
    1118                 : nsresult
    1119               2 : nsFaviconService::GetFaviconDataAsync(nsIURI* aFaviconURI,
    1120                 :                                       mozIStorageStatementCallback *aCallback)
    1121                 : {
    1122               2 :   NS_ASSERTION(aCallback, "Doesn't make sense to call this without a callback");
    1123                 :   nsCOMPtr<mozIStorageAsyncStatement> stmt = mDB->GetAsyncStatement(
    1124                 :     "SELECT f.data, f.mime_type FROM moz_favicons f WHERE url = :icon_url"
    1125               4 :   );
    1126               2 :   NS_ENSURE_STATE(stmt);
    1127                 : 
    1128               2 :   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
    1129               2 :   NS_ENSURE_SUCCESS(rv, rv);
    1130                 : 
    1131               4 :   nsCOMPtr<mozIStoragePendingStatement> pendingStatement;
    1132               2 :   return stmt->ExecuteAsync(aCallback, getter_AddRefs(pendingStatement));
    1133                 : }
    1134                 : 
    1135                 : ////////////////////////////////////////////////////////////////////////////////
    1136                 : //// ExpireFaviconsStatementCallbackNotifier
    1137                 : 
    1138               1 : ExpireFaviconsStatementCallbackNotifier::ExpireFaviconsStatementCallbackNotifier(
    1139                 :   bool* aFaviconsExpirationRunning)
    1140               1 : : mFaviconsExpirationRunning(aFaviconsExpirationRunning)
    1141                 : {
    1142               1 :   NS_ASSERTION(mFaviconsExpirationRunning, "Pointer to bool mFaviconsExpirationRunning can't be null");
    1143               1 : }
    1144                 : 
    1145                 : 
    1146                 : NS_IMETHODIMP
    1147               1 : ExpireFaviconsStatementCallbackNotifier::HandleCompletion(PRUint16 aReason)
    1148                 : {
    1149               1 :   *mFaviconsExpirationRunning = false;
    1150                 : 
    1151                 :   // We should dispatch only if expiration has been successful.
    1152               1 :   if (aReason != mozIStorageStatementCallback::REASON_FINISHED)
    1153               0 :     return NS_OK;
    1154                 : 
    1155                 :   nsCOMPtr<nsIObserverService> observerService =
    1156               2 :     mozilla::services::GetObserverService();
    1157               1 :   if (observerService) {
    1158               1 :     (void)observerService->NotifyObservers(nsnull,
    1159                 :                                            NS_PLACES_FAVICONS_EXPIRED_TOPIC_ID,
    1160               1 :                                            nsnull);
    1161                 :   }
    1162                 : 
    1163               1 :   return NS_OK;
    1164                 : }

Generated by: LCOV version 1.7