toolkit/components/places/nsFaviconService.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 /**
michael@0 7 * This is the favicon service, which stores favicons for web pages with your
michael@0 8 * history as you browse. It is also used to save the favicons for bookmarks.
michael@0 9 *
michael@0 10 * DANGER: The history query system makes assumptions about the favicon storage
michael@0 11 * so that icons can be quickly generated for history/bookmark result sets. If
michael@0 12 * you change the database layout at all, you will have to update both services.
michael@0 13 */
michael@0 14
michael@0 15 #include "nsFaviconService.h"
michael@0 16
michael@0 17 #include "nsNavHistory.h"
michael@0 18 #include "nsPlacesMacros.h"
michael@0 19 #include "Helpers.h"
michael@0 20 #include "AsyncFaviconHelpers.h"
michael@0 21
michael@0 22 #include "nsNetUtil.h"
michael@0 23 #include "nsReadableUtils.h"
michael@0 24 #include "nsStreamUtils.h"
michael@0 25 #include "nsStringStream.h"
michael@0 26 #include "plbase64.h"
michael@0 27 #include "nsIClassInfoImpl.h"
michael@0 28 #include "mozilla/ArrayUtils.h"
michael@0 29 #include "mozilla/Preferences.h"
michael@0 30
michael@0 31 // For large favicons optimization.
michael@0 32 #include "imgITools.h"
michael@0 33 #include "imgIContainer.h"
michael@0 34
michael@0 35 // Default value for mOptimizedIconDimension
michael@0 36 #define OPTIMIZED_FAVICON_DIMENSION 16
michael@0 37
michael@0 38 #define MAX_FAVICON_CACHE_SIZE 256
michael@0 39 #define FAVICON_CACHE_REDUCE_COUNT 64
michael@0 40
michael@0 41 #define MAX_UNASSOCIATED_FAVICONS 64
michael@0 42
michael@0 43 // When replaceFaviconData is called, we store the icons in an in-memory cache
michael@0 44 // instead of in storage. Icons in the cache are expired according to this
michael@0 45 // interval.
michael@0 46 #define UNASSOCIATED_ICON_EXPIRY_INTERVAL 60000
michael@0 47
michael@0 48 // The MIME type of the default favicon and favicons created by
michael@0 49 // OptimizeFaviconImage.
michael@0 50 #define DEFAULT_MIME_TYPE "image/png"
michael@0 51
michael@0 52 using namespace mozilla;
michael@0 53 using namespace mozilla::places;
michael@0 54
michael@0 55 /**
michael@0 56 * Used to notify a topic to system observers on async execute completion.
michael@0 57 * Will throw on error.
michael@0 58 */
michael@0 59 class ExpireFaviconsStatementCallbackNotifier : public AsyncStatementCallback
michael@0 60 {
michael@0 61 public:
michael@0 62 ExpireFaviconsStatementCallbackNotifier();
michael@0 63 NS_IMETHOD HandleCompletion(uint16_t aReason);
michael@0 64 };
michael@0 65
michael@0 66
michael@0 67 PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsFaviconService, gFaviconService)
michael@0 68
michael@0 69 NS_IMPL_CLASSINFO(nsFaviconService, nullptr, 0, NS_FAVICONSERVICE_CID)
michael@0 70 NS_IMPL_ISUPPORTS_CI(
michael@0 71 nsFaviconService
michael@0 72 , nsIFaviconService
michael@0 73 , mozIAsyncFavicons
michael@0 74 , nsITimerCallback
michael@0 75 )
michael@0 76
michael@0 77 nsFaviconService::nsFaviconService()
michael@0 78 : mOptimizedIconDimension(OPTIMIZED_FAVICON_DIMENSION)
michael@0 79 , mFailedFaviconSerial(0)
michael@0 80 , mFailedFavicons(MAX_FAVICON_CACHE_SIZE)
michael@0 81 , mUnassociatedIcons(MAX_UNASSOCIATED_FAVICONS)
michael@0 82 {
michael@0 83 NS_ASSERTION(!gFaviconService,
michael@0 84 "Attempting to create two instances of the service!");
michael@0 85 gFaviconService = this;
michael@0 86 }
michael@0 87
michael@0 88
michael@0 89 nsFaviconService::~nsFaviconService()
michael@0 90 {
michael@0 91 NS_ASSERTION(gFaviconService == this,
michael@0 92 "Deleting a non-singleton instance of the service");
michael@0 93 if (gFaviconService == this)
michael@0 94 gFaviconService = nullptr;
michael@0 95 }
michael@0 96
michael@0 97
michael@0 98 nsresult
michael@0 99 nsFaviconService::Init()
michael@0 100 {
michael@0 101 mDB = Database::GetDatabase();
michael@0 102 NS_ENSURE_STATE(mDB);
michael@0 103
michael@0 104 mOptimizedIconDimension = Preferences::GetInt(
michael@0 105 "places.favicons.optimizeToDimension", OPTIMIZED_FAVICON_DIMENSION
michael@0 106 );
michael@0 107
michael@0 108 mExpireUnassociatedIconsTimer = do_CreateInstance("@mozilla.org/timer;1");
michael@0 109 NS_ENSURE_STATE(mExpireUnassociatedIconsTimer);
michael@0 110
michael@0 111 return NS_OK;
michael@0 112 }
michael@0 113
michael@0 114 NS_IMETHODIMP
michael@0 115 nsFaviconService::ExpireAllFavicons()
michael@0 116 {
michael@0 117 nsCOMPtr<mozIStorageAsyncStatement> unlinkIconsStmt = mDB->GetAsyncStatement(
michael@0 118 "UPDATE moz_places "
michael@0 119 "SET favicon_id = NULL "
michael@0 120 "WHERE favicon_id NOT NULL"
michael@0 121 );
michael@0 122 NS_ENSURE_STATE(unlinkIconsStmt);
michael@0 123 nsCOMPtr<mozIStorageAsyncStatement> removeIconsStmt = mDB->GetAsyncStatement(
michael@0 124 "DELETE FROM moz_favicons WHERE id NOT IN ("
michael@0 125 "SELECT favicon_id FROM moz_places WHERE favicon_id NOT NULL "
michael@0 126 ")"
michael@0 127 );
michael@0 128 NS_ENSURE_STATE(removeIconsStmt);
michael@0 129
michael@0 130 mozIStorageBaseStatement* stmts[] = {
michael@0 131 unlinkIconsStmt.get()
michael@0 132 , removeIconsStmt.get()
michael@0 133 };
michael@0 134 nsCOMPtr<mozIStoragePendingStatement> ps;
michael@0 135 nsRefPtr<ExpireFaviconsStatementCallbackNotifier> callback =
michael@0 136 new ExpireFaviconsStatementCallbackNotifier();
michael@0 137 nsresult rv = mDB->MainConn()->ExecuteAsync(
michael@0 138 stmts, ArrayLength(stmts), callback, getter_AddRefs(ps)
michael@0 139 );
michael@0 140 NS_ENSURE_SUCCESS(rv, rv);
michael@0 141
michael@0 142 return NS_OK;
michael@0 143 }
michael@0 144
michael@0 145 ////////////////////////////////////////////////////////////////////////////////
michael@0 146 //// nsITimerCallback
michael@0 147
michael@0 148 static PLDHashOperator
michael@0 149 ExpireNonrecentUnassociatedIconsEnumerator(
michael@0 150 UnassociatedIconHashKey* aIconKey,
michael@0 151 void* aNow)
michael@0 152 {
michael@0 153 PRTime now = *(reinterpret_cast<PRTime*>(aNow));
michael@0 154 if (now - aIconKey->created >= UNASSOCIATED_ICON_EXPIRY_INTERVAL) {
michael@0 155 return PL_DHASH_REMOVE;
michael@0 156 }
michael@0 157 return PL_DHASH_NEXT;
michael@0 158 }
michael@0 159
michael@0 160 NS_IMETHODIMP
michael@0 161 nsFaviconService::Notify(nsITimer* timer)
michael@0 162 {
michael@0 163 if (timer != mExpireUnassociatedIconsTimer.get()) {
michael@0 164 return NS_ERROR_INVALID_ARG;
michael@0 165 }
michael@0 166
michael@0 167 PRTime now = PR_Now();
michael@0 168 mUnassociatedIcons.EnumerateEntries(
michael@0 169 ExpireNonrecentUnassociatedIconsEnumerator, &now);
michael@0 170 // Re-init the expiry timer if the cache isn't empty.
michael@0 171 if (mUnassociatedIcons.Count() > 0) {
michael@0 172 mExpireUnassociatedIconsTimer->InitWithCallback(
michael@0 173 this, UNASSOCIATED_ICON_EXPIRY_INTERVAL, nsITimer::TYPE_ONE_SHOT);
michael@0 174 }
michael@0 175
michael@0 176 return NS_OK;
michael@0 177 }
michael@0 178
michael@0 179 ////////////////////////////////////////////////////////////////////////////////
michael@0 180 //// nsIFaviconService
michael@0 181
michael@0 182 NS_IMETHODIMP
michael@0 183 nsFaviconService::GetDefaultFavicon(nsIURI** _retval)
michael@0 184 {
michael@0 185 NS_ENSURE_ARG_POINTER(_retval);
michael@0 186
michael@0 187 // not found, use default
michael@0 188 if (!mDefaultIcon) {
michael@0 189 nsresult rv = NS_NewURI(getter_AddRefs(mDefaultIcon),
michael@0 190 NS_LITERAL_CSTRING(FAVICON_DEFAULT_URL));
michael@0 191 NS_ENSURE_SUCCESS(rv, rv);
michael@0 192 }
michael@0 193 return mDefaultIcon->Clone(_retval);
michael@0 194 }
michael@0 195
michael@0 196 void
michael@0 197 nsFaviconService::SendFaviconNotifications(nsIURI* aPageURI,
michael@0 198 nsIURI* aFaviconURI,
michael@0 199 const nsACString& aGUID)
michael@0 200 {
michael@0 201 nsAutoCString faviconSpec;
michael@0 202 nsNavHistory* history = nsNavHistory::GetHistoryService();
michael@0 203 if (history && NS_SUCCEEDED(aFaviconURI->GetSpec(faviconSpec))) {
michael@0 204 history->SendPageChangedNotification(aPageURI,
michael@0 205 nsINavHistoryObserver::ATTRIBUTE_FAVICON,
michael@0 206 NS_ConvertUTF8toUTF16(faviconSpec),
michael@0 207 aGUID);
michael@0 208 }
michael@0 209 }
michael@0 210
michael@0 211 NS_IMETHODIMP
michael@0 212 nsFaviconService::SetAndFetchFaviconForPage(nsIURI* aPageURI,
michael@0 213 nsIURI* aFaviconURI,
michael@0 214 bool aForceReload,
michael@0 215 uint32_t aFaviconLoadType,
michael@0 216 nsIFaviconDataCallback* aCallback)
michael@0 217 {
michael@0 218 NS_ENSURE_ARG(aPageURI);
michael@0 219 NS_ENSURE_ARG(aFaviconURI);
michael@0 220
michael@0 221 // If a favicon is in the failed cache, only load it during a forced reload.
michael@0 222 bool previouslyFailed;
michael@0 223 nsresult rv = IsFailedFavicon(aFaviconURI, &previouslyFailed);
michael@0 224 NS_ENSURE_SUCCESS(rv, rv);
michael@0 225 if (previouslyFailed) {
michael@0 226 if (aForceReload)
michael@0 227 RemoveFailedFavicon(aFaviconURI);
michael@0 228 else
michael@0 229 return NS_OK;
michael@0 230 }
michael@0 231
michael@0 232 // Check if the icon already exists and fetch it from the network, if needed.
michael@0 233 // Finally associate the icon to the requested page if not yet associated.
michael@0 234 rv = AsyncFetchAndSetIconForPage::start(
michael@0 235 aFaviconURI, aPageURI, aForceReload ? FETCH_ALWAYS : FETCH_IF_MISSING,
michael@0 236 aFaviconLoadType, aCallback
michael@0 237 );
michael@0 238 NS_ENSURE_SUCCESS(rv, rv);
michael@0 239
michael@0 240 // DB will be updated and observers notified when data has finished loading.
michael@0 241 return NS_OK;
michael@0 242 }
michael@0 243
michael@0 244 NS_IMETHODIMP
michael@0 245 nsFaviconService::ReplaceFaviconData(nsIURI* aFaviconURI,
michael@0 246 const uint8_t* aData,
michael@0 247 uint32_t aDataLen,
michael@0 248 const nsACString& aMimeType,
michael@0 249 PRTime aExpiration)
michael@0 250 {
michael@0 251 NS_ENSURE_ARG(aFaviconURI);
michael@0 252 NS_ENSURE_ARG(aData);
michael@0 253 NS_ENSURE_TRUE(aDataLen > 0, NS_ERROR_INVALID_ARG);
michael@0 254 NS_ENSURE_TRUE(aMimeType.Length() > 0, NS_ERROR_INVALID_ARG);
michael@0 255 if (aExpiration == 0) {
michael@0 256 aExpiration = PR_Now() + MAX_FAVICON_EXPIRATION;
michael@0 257 }
michael@0 258
michael@0 259 UnassociatedIconHashKey* iconKey = mUnassociatedIcons.PutEntry(aFaviconURI);
michael@0 260 if (!iconKey) {
michael@0 261 return NS_ERROR_OUT_OF_MEMORY;
michael@0 262 }
michael@0 263
michael@0 264 iconKey->created = PR_Now();
michael@0 265
michael@0 266 // If the cache contains unassociated icons, an expiry timer should already exist, otherwise
michael@0 267 // there may be a timer left hanging around, so make sure we fire a new one.
michael@0 268 int32_t unassociatedCount = mUnassociatedIcons.Count();
michael@0 269 if (unassociatedCount == 1) {
michael@0 270 mExpireUnassociatedIconsTimer->Cancel();
michael@0 271 mExpireUnassociatedIconsTimer->InitWithCallback(
michael@0 272 this, UNASSOCIATED_ICON_EXPIRY_INTERVAL, nsITimer::TYPE_ONE_SHOT);
michael@0 273 }
michael@0 274
michael@0 275 IconData* iconData = &(iconKey->iconData);
michael@0 276 iconData->expiration = aExpiration;
michael@0 277 iconData->status = ICON_STATUS_CACHED;
michael@0 278 iconData->fetchMode = FETCH_NEVER;
michael@0 279 nsresult rv = aFaviconURI->GetSpec(iconData->spec);
michael@0 280 NS_ENSURE_SUCCESS(rv, rv);
michael@0 281
michael@0 282 // If the page provided a large image for the favicon (eg, a highres image
michael@0 283 // or a multiresolution .ico file), we don't want to store more data than
michael@0 284 // needed.
michael@0 285 if (aDataLen > MAX_ICON_FILESIZE(mOptimizedIconDimension)) {
michael@0 286 rv = OptimizeFaviconImage(aData, aDataLen, aMimeType, iconData->data, iconData->mimeType);
michael@0 287 NS_ENSURE_SUCCESS(rv, rv);
michael@0 288
michael@0 289 if (iconData->data.Length() > MAX_FAVICON_SIZE) {
michael@0 290 // We cannot optimize this favicon size and we are over the maximum size
michael@0 291 // allowed, so we will not save data to the db to avoid bloating it.
michael@0 292 mUnassociatedIcons.RemoveEntry(aFaviconURI);
michael@0 293 return NS_ERROR_FAILURE;
michael@0 294 }
michael@0 295 } else {
michael@0 296 iconData->mimeType.Assign(aMimeType);
michael@0 297 iconData->data.Assign(TO_CHARBUFFER(aData), aDataLen);
michael@0 298 }
michael@0 299
michael@0 300 // If the database contains an icon at the given url, we will update the
michael@0 301 // database immediately so that the associated pages are kept in sync.
michael@0 302 // Otherwise, do nothing and let the icon be picked up from the memory hash.
michael@0 303 rv = AsyncReplaceFaviconData::start(iconData);
michael@0 304 NS_ENSURE_SUCCESS(rv, rv);
michael@0 305
michael@0 306 return NS_OK;
michael@0 307 }
michael@0 308
michael@0 309 NS_IMETHODIMP
michael@0 310 nsFaviconService::ReplaceFaviconDataFromDataURL(nsIURI* aFaviconURI,
michael@0 311 const nsAString& aDataURL,
michael@0 312 PRTime aExpiration)
michael@0 313 {
michael@0 314 NS_ENSURE_ARG(aFaviconURI);
michael@0 315 NS_ENSURE_TRUE(aDataURL.Length() > 0, NS_ERROR_INVALID_ARG);
michael@0 316 if (aExpiration == 0) {
michael@0 317 aExpiration = PR_Now() + MAX_FAVICON_EXPIRATION;
michael@0 318 }
michael@0 319
michael@0 320 nsCOMPtr<nsIURI> dataURI;
michael@0 321 nsresult rv = NS_NewURI(getter_AddRefs(dataURI), aDataURL);
michael@0 322 NS_ENSURE_SUCCESS(rv, rv);
michael@0 323
michael@0 324 // Use the data: protocol handler to convert the data.
michael@0 325 nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
michael@0 326 NS_ENSURE_SUCCESS(rv, rv);
michael@0 327 nsCOMPtr<nsIProtocolHandler> protocolHandler;
michael@0 328 rv = ioService->GetProtocolHandler("data", getter_AddRefs(protocolHandler));
michael@0 329 NS_ENSURE_SUCCESS(rv, rv);
michael@0 330
michael@0 331 nsCOMPtr<nsIChannel> channel;
michael@0 332 rv = protocolHandler->NewChannel(dataURI, getter_AddRefs(channel));
michael@0 333 NS_ENSURE_SUCCESS(rv, rv);
michael@0 334
michael@0 335 // Blocking stream is OK for data URIs.
michael@0 336 nsCOMPtr<nsIInputStream> stream;
michael@0 337 rv = channel->Open(getter_AddRefs(stream));
michael@0 338 NS_ENSURE_SUCCESS(rv, rv);
michael@0 339
michael@0 340 uint64_t available64;
michael@0 341 rv = stream->Available(&available64);
michael@0 342 NS_ENSURE_SUCCESS(rv, rv);
michael@0 343 if (available64 == 0 || available64 > UINT32_MAX / sizeof(uint8_t))
michael@0 344 return NS_ERROR_FILE_TOO_BIG;
michael@0 345 uint32_t available = (uint32_t)available64;
michael@0 346
michael@0 347 // Read all the decoded data.
michael@0 348 uint8_t* buffer = static_cast<uint8_t*>
michael@0 349 (nsMemory::Alloc(sizeof(uint8_t) * available));
michael@0 350 if (!buffer)
michael@0 351 return NS_ERROR_OUT_OF_MEMORY;
michael@0 352 uint32_t numRead;
michael@0 353 rv = stream->Read(TO_CHARBUFFER(buffer), available, &numRead);
michael@0 354 if (NS_FAILED(rv) || numRead != available) {
michael@0 355 nsMemory::Free(buffer);
michael@0 356 return rv;
michael@0 357 }
michael@0 358
michael@0 359 nsAutoCString mimeType;
michael@0 360 rv = channel->GetContentType(mimeType);
michael@0 361 if (NS_FAILED(rv)) {
michael@0 362 nsMemory::Free(buffer);
michael@0 363 return rv;
michael@0 364 }
michael@0 365
michael@0 366 // ReplaceFaviconData can now do the dirty work.
michael@0 367 rv = ReplaceFaviconData(aFaviconURI, buffer, available, mimeType, aExpiration);
michael@0 368 nsMemory::Free(buffer);
michael@0 369 NS_ENSURE_SUCCESS(rv, rv);
michael@0 370
michael@0 371 return NS_OK;
michael@0 372 }
michael@0 373
michael@0 374 NS_IMETHODIMP
michael@0 375 nsFaviconService::GetFaviconURLForPage(nsIURI *aPageURI,
michael@0 376 nsIFaviconDataCallback* aCallback)
michael@0 377 {
michael@0 378 NS_ENSURE_ARG(aPageURI);
michael@0 379 NS_ENSURE_ARG(aCallback);
michael@0 380
michael@0 381 nsresult rv = AsyncGetFaviconURLForPage::start(aPageURI, aCallback);
michael@0 382 NS_ENSURE_SUCCESS(rv, rv);
michael@0 383 return NS_OK;
michael@0 384 }
michael@0 385
michael@0 386 NS_IMETHODIMP
michael@0 387 nsFaviconService::GetFaviconDataForPage(nsIURI* aPageURI,
michael@0 388 nsIFaviconDataCallback* aCallback)
michael@0 389 {
michael@0 390 NS_ENSURE_ARG(aPageURI);
michael@0 391 NS_ENSURE_ARG(aCallback);
michael@0 392
michael@0 393 nsresult rv = AsyncGetFaviconDataForPage::start(aPageURI, aCallback);
michael@0 394 NS_ENSURE_SUCCESS(rv, rv);
michael@0 395 return NS_OK;
michael@0 396 }
michael@0 397
michael@0 398 nsresult
michael@0 399 nsFaviconService::GetFaviconLinkForIcon(nsIURI* aFaviconURI,
michael@0 400 nsIURI** aOutputURI)
michael@0 401 {
michael@0 402 NS_ENSURE_ARG(aFaviconURI);
michael@0 403 NS_ENSURE_ARG_POINTER(aOutputURI);
michael@0 404
michael@0 405 nsAutoCString spec;
michael@0 406 if (aFaviconURI) {
michael@0 407 nsresult rv = aFaviconURI->GetSpec(spec);
michael@0 408 NS_ENSURE_SUCCESS(rv, rv);
michael@0 409 }
michael@0 410 return GetFaviconLinkForIconString(spec, aOutputURI);
michael@0 411 }
michael@0 412
michael@0 413
michael@0 414 static PLDHashOperator
michael@0 415 ExpireFailedFaviconsCallback(nsCStringHashKey::KeyType aKey,
michael@0 416 uint32_t& aData,
michael@0 417 void* userArg)
michael@0 418 {
michael@0 419 uint32_t* threshold = reinterpret_cast<uint32_t*>(userArg);
michael@0 420 if (aData < *threshold)
michael@0 421 return PL_DHASH_REMOVE;
michael@0 422 return PL_DHASH_NEXT;
michael@0 423 }
michael@0 424
michael@0 425
michael@0 426 NS_IMETHODIMP
michael@0 427 nsFaviconService::AddFailedFavicon(nsIURI* aFaviconURI)
michael@0 428 {
michael@0 429 NS_ENSURE_ARG(aFaviconURI);
michael@0 430
michael@0 431 nsAutoCString spec;
michael@0 432 nsresult rv = aFaviconURI->GetSpec(spec);
michael@0 433 NS_ENSURE_SUCCESS(rv, rv);
michael@0 434
michael@0 435 mFailedFavicons.Put(spec, mFailedFaviconSerial);
michael@0 436 mFailedFaviconSerial ++;
michael@0 437
michael@0 438 if (mFailedFavicons.Count() > MAX_FAVICON_CACHE_SIZE) {
michael@0 439 // need to expire some entries, delete the FAVICON_CACHE_REDUCE_COUNT number
michael@0 440 // of items that are the oldest
michael@0 441 uint32_t threshold = mFailedFaviconSerial -
michael@0 442 MAX_FAVICON_CACHE_SIZE + FAVICON_CACHE_REDUCE_COUNT;
michael@0 443 mFailedFavicons.Enumerate(ExpireFailedFaviconsCallback, &threshold);
michael@0 444 }
michael@0 445 return NS_OK;
michael@0 446 }
michael@0 447
michael@0 448
michael@0 449 NS_IMETHODIMP
michael@0 450 nsFaviconService::RemoveFailedFavicon(nsIURI* aFaviconURI)
michael@0 451 {
michael@0 452 NS_ENSURE_ARG(aFaviconURI);
michael@0 453
michael@0 454 nsAutoCString spec;
michael@0 455 nsresult rv = aFaviconURI->GetSpec(spec);
michael@0 456 NS_ENSURE_SUCCESS(rv, rv);
michael@0 457
michael@0 458 // we silently do nothing and succeed if the icon is not in the cache
michael@0 459 mFailedFavicons.Remove(spec);
michael@0 460 return NS_OK;
michael@0 461 }
michael@0 462
michael@0 463
michael@0 464 NS_IMETHODIMP
michael@0 465 nsFaviconService::IsFailedFavicon(nsIURI* aFaviconURI, bool* _retval)
michael@0 466 {
michael@0 467 NS_ENSURE_ARG(aFaviconURI);
michael@0 468 nsAutoCString spec;
michael@0 469 nsresult rv = aFaviconURI->GetSpec(spec);
michael@0 470 NS_ENSURE_SUCCESS(rv, rv);
michael@0 471
michael@0 472 uint32_t serial;
michael@0 473 *_retval = mFailedFavicons.Get(spec, &serial);
michael@0 474 return NS_OK;
michael@0 475 }
michael@0 476
michael@0 477
michael@0 478 // nsFaviconService::GetFaviconLinkForIconString
michael@0 479 //
michael@0 480 // This computes a favicon URL with string input and using the cached
michael@0 481 // default one to minimize parsing.
michael@0 482
michael@0 483 nsresult
michael@0 484 nsFaviconService::GetFaviconLinkForIconString(const nsCString& aSpec,
michael@0 485 nsIURI** aOutput)
michael@0 486 {
michael@0 487 if (aSpec.IsEmpty()) {
michael@0 488 // default icon for empty strings
michael@0 489 if (! mDefaultIcon) {
michael@0 490 nsresult rv = NS_NewURI(getter_AddRefs(mDefaultIcon),
michael@0 491 NS_LITERAL_CSTRING(FAVICON_DEFAULT_URL));
michael@0 492 NS_ENSURE_SUCCESS(rv, rv);
michael@0 493 }
michael@0 494 return mDefaultIcon->Clone(aOutput);
michael@0 495 }
michael@0 496
michael@0 497 if (StringBeginsWith(aSpec, NS_LITERAL_CSTRING("chrome:"))) {
michael@0 498 // pass through for chrome URLs, since they can be referenced without
michael@0 499 // this service
michael@0 500 return NS_NewURI(aOutput, aSpec);
michael@0 501 }
michael@0 502
michael@0 503 nsAutoCString annoUri;
michael@0 504 annoUri.AssignLiteral("moz-anno:" FAVICON_ANNOTATION_NAME ":");
michael@0 505 annoUri += aSpec;
michael@0 506 return NS_NewURI(aOutput, annoUri);
michael@0 507 }
michael@0 508
michael@0 509
michael@0 510 // nsFaviconService::GetFaviconSpecForIconString
michael@0 511 //
michael@0 512 // This computes a favicon spec for when you don't want a URI object (as in
michael@0 513 // the tree view implementation), sparing all parsing and normalization.
michael@0 514 void
michael@0 515 nsFaviconService::GetFaviconSpecForIconString(const nsCString& aSpec,
michael@0 516 nsACString& aOutput)
michael@0 517 {
michael@0 518 if (aSpec.IsEmpty()) {
michael@0 519 aOutput.AssignLiteral(FAVICON_DEFAULT_URL);
michael@0 520 } else if (StringBeginsWith(aSpec, NS_LITERAL_CSTRING("chrome:"))) {
michael@0 521 aOutput = aSpec;
michael@0 522 } else {
michael@0 523 aOutput.AssignLiteral("moz-anno:" FAVICON_ANNOTATION_NAME ":");
michael@0 524 aOutput += aSpec;
michael@0 525 }
michael@0 526 }
michael@0 527
michael@0 528
michael@0 529 // nsFaviconService::OptimizeFaviconImage
michael@0 530 //
michael@0 531 // Given a blob of data (a image file already read into a buffer), optimize
michael@0 532 // its size by recompressing it as a 16x16 PNG.
michael@0 533 nsresult
michael@0 534 nsFaviconService::OptimizeFaviconImage(const uint8_t* aData, uint32_t aDataLen,
michael@0 535 const nsACString& aMimeType,
michael@0 536 nsACString& aNewData,
michael@0 537 nsACString& aNewMimeType)
michael@0 538 {
michael@0 539 nsresult rv;
michael@0 540
michael@0 541 nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1");
michael@0 542
michael@0 543 nsCOMPtr<nsIInputStream> stream;
michael@0 544 rv = NS_NewByteInputStream(getter_AddRefs(stream),
michael@0 545 reinterpret_cast<const char*>(aData), aDataLen,
michael@0 546 NS_ASSIGNMENT_DEPEND);
michael@0 547 NS_ENSURE_SUCCESS(rv, rv);
michael@0 548
michael@0 549 // decode image
michael@0 550 nsCOMPtr<imgIContainer> container;
michael@0 551 rv = imgtool->DecodeImageData(stream, aMimeType, getter_AddRefs(container));
michael@0 552 NS_ENSURE_SUCCESS(rv, rv);
michael@0 553
michael@0 554 aNewMimeType.AssignLiteral(DEFAULT_MIME_TYPE);
michael@0 555
michael@0 556 // scale and recompress
michael@0 557 nsCOMPtr<nsIInputStream> iconStream;
michael@0 558 rv = imgtool->EncodeScaledImage(container, aNewMimeType,
michael@0 559 mOptimizedIconDimension,
michael@0 560 mOptimizedIconDimension,
michael@0 561 EmptyString(),
michael@0 562 getter_AddRefs(iconStream));
michael@0 563 NS_ENSURE_SUCCESS(rv, rv);
michael@0 564
michael@0 565 // Read the stream into a new buffer.
michael@0 566 rv = NS_ConsumeStream(iconStream, UINT32_MAX, aNewData);
michael@0 567 NS_ENSURE_SUCCESS(rv, rv);
michael@0 568
michael@0 569 return NS_OK;
michael@0 570 }
michael@0 571
michael@0 572 nsresult
michael@0 573 nsFaviconService::GetFaviconDataAsync(nsIURI* aFaviconURI,
michael@0 574 mozIStorageStatementCallback *aCallback)
michael@0 575 {
michael@0 576 NS_ASSERTION(aCallback, "Doesn't make sense to call this without a callback");
michael@0 577 nsCOMPtr<mozIStorageAsyncStatement> stmt = mDB->GetAsyncStatement(
michael@0 578 "SELECT f.data, f.mime_type FROM moz_favicons f WHERE url = :icon_url"
michael@0 579 );
michael@0 580 NS_ENSURE_STATE(stmt);
michael@0 581
michael@0 582 nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
michael@0 583 NS_ENSURE_SUCCESS(rv, rv);
michael@0 584
michael@0 585 nsCOMPtr<mozIStoragePendingStatement> pendingStatement;
michael@0 586 return stmt->ExecuteAsync(aCallback, getter_AddRefs(pendingStatement));
michael@0 587 }
michael@0 588
michael@0 589 ////////////////////////////////////////////////////////////////////////////////
michael@0 590 //// ExpireFaviconsStatementCallbackNotifier
michael@0 591
michael@0 592 ExpireFaviconsStatementCallbackNotifier::ExpireFaviconsStatementCallbackNotifier()
michael@0 593 {
michael@0 594 }
michael@0 595
michael@0 596
michael@0 597 NS_IMETHODIMP
michael@0 598 ExpireFaviconsStatementCallbackNotifier::HandleCompletion(uint16_t aReason)
michael@0 599 {
michael@0 600 // We should dispatch only if expiration has been successful.
michael@0 601 if (aReason != mozIStorageStatementCallback::REASON_FINISHED)
michael@0 602 return NS_OK;
michael@0 603
michael@0 604 nsCOMPtr<nsIObserverService> observerService =
michael@0 605 mozilla::services::GetObserverService();
michael@0 606 if (observerService) {
michael@0 607 (void)observerService->NotifyObservers(nullptr,
michael@0 608 NS_PLACES_FAVICONS_EXPIRED_TOPIC_ID,
michael@0 609 nullptr);
michael@0 610 }
michael@0 611
michael@0 612 return NS_OK;
michael@0 613 }

mercurial