NS_IMETHODIMP nsFaviconService::GetFaviconImageForPage(nsIURI* aPageURI, nsIURI** _retval) { mozStorageStatementScoper scoper(mDBGetURL); nsresult rv = BindStatementURI(mDBGetURL, 0, aPageURI); NS_ENSURE_SUCCESS(rv, rv); PRBool hasResult; nsCOMPtr<nsIURI> faviconURI; if (NS_SUCCEEDED(mDBGetURL->ExecuteStep(&hasResult)) && hasResult) { PRInt32 dataLen; rv = mDBGetURL->GetInt32(2, &dataLen); NS_ENSURE_SUCCESS(rv, rv); if (dataLen > 0) { // this page has a favicon entry with data nsCAutoString favIconUri; rv = mDBGetURL->GetUTF8String(1, favIconUri); NS_ENSURE_SUCCESS(rv, rv); return GetFaviconLinkForIconString(favIconUri, _retval); } } // not found, use default return GetDefaultFavicon(_retval); }
NS_IMETHODIMP nsFaviconService::GetFaviconForPage(nsIURI* aPageURI, nsIURI** _retval) { mozStorageStatementScoper scoper(mDBGetURL); nsresult rv = BindStatementURI(mDBGetURL, 0, aPageURI); NS_ENSURE_SUCCESS(rv, rv); PRBool hasResult; if (NS_SUCCEEDED(mDBGetURL->ExecuteStep(&hasResult)) && hasResult) { nsCAutoString url; rv = mDBGetURL->GetUTF8String(1, url); NS_ENSURE_SUCCESS(rv, rv); return NS_NewURI(_retval, url); } return NS_ERROR_NOT_AVAILABLE; }
NS_IMETHODIMP nsFaviconService::GetFaviconData(nsIURI* aFaviconURI, nsACString& aMimeType, PRUint32* aDataLen, PRUint8** aData) { mozStorageStatementScoper scoper(mDBGetData); nsresult rv = BindStatementURI(mDBGetData, 0, aFaviconURI); NS_ENSURE_SUCCESS(rv, rv); PRBool hasResult = PR_FALSE; if (NS_SUCCEEDED(mDBGetData->ExecuteStep(&hasResult)) && hasResult) { rv = mDBGetData->GetUTF8String(1, aMimeType); NS_ENSURE_SUCCESS(rv, rv); return mDBGetData->GetBlob(0, aDataLen, aData); } return NS_ERROR_NOT_AVAILABLE; }
nsresult nsAnnotationService::StartGetAnnotationFromURI(nsIURI* aURI, const nsACString& aName) { mozStorageStatementScoper statementResetter(mDBGetAnnotationFromURI); nsresult rv; rv = BindStatementURI(mDBGetAnnotationFromURI, 0, aURI); NS_ENSURE_SUCCESS(rv, rv); rv = mDBGetAnnotationFromURI->BindUTF8StringParameter(1, aName); NS_ENSURE_SUCCESS(rv, rv); PRBool hasResult = PR_FALSE; rv = mDBGetAnnotationFromURI->ExecuteStep(&hasResult); if (NS_FAILED(rv) || ! hasResult) return NS_ERROR_NOT_AVAILABLE; // on success, DON'T reset the statement, the caller needs to read from it, // and it is the caller's job to do the reseting. statementResetter.Abandon(); return NS_OK; }
NS_IMETHODIMP nsFaviconService::SetFaviconData(nsIURI* aFaviconURI, const PRUint8* aData, PRUint32 aDataLen, const nsACString& aMimeType, PRTime aExpiration) { nsresult rv; PRUint32 dataLen = aDataLen; const PRUint8* data = aData; const nsACString* mimeType = &aMimeType; nsCString newData, newMimeType; // If the page provided a large image for the favicon (eg, a highres image // or a multiresolution .ico file), we don't want to store more data than // needed. An uncompressed 16x16 RGBA image is 1024 bytes, and almost all // sensible 16x16 icons are under 1024 bytes. if (aDataLen > 1024) { rv = OptimizeFaviconImage(aData, aDataLen, aMimeType, newData, newMimeType); if (NS_SUCCEEDED(rv) && newData.Length() < aDataLen) { data = reinterpret_cast<PRUint8*>(const_cast<char*>(newData.get())), dataLen = newData.Length(); mimeType = &newMimeType; } } mozIStorageStatement* statement; { // this block forces the scoper to reset our statement: necessary for the // next statement mozStorageStatementScoper scoper(mDBGetIconInfo); rv = BindStatementURI(mDBGetIconInfo, 0, aFaviconURI); NS_ENSURE_SUCCESS(rv, rv); PRBool hasResult; rv = mDBGetIconInfo->ExecuteStep(&hasResult); NS_ENSURE_SUCCESS(rv, rv); if (hasResult) { // update old one (statement parameter 0 = ID) PRInt64 id; rv = mDBGetIconInfo->GetInt64(0, &id); NS_ENSURE_SUCCESS(rv, rv); statement = mDBUpdateIcon; rv = statement->BindInt64Parameter(0, id); } else { // insert new one (statement parameter 0 = favicon URL) statement = mDBInsertIcon; rv = BindStatementURI(statement, 0, aFaviconURI); } NS_ENSURE_SUCCESS(rv, rv); } mozStorageStatementScoper scoper(statement); // the insert and update statements share all but the 0th parameter rv = statement->BindBlobParameter(1, data, dataLen); NS_ENSURE_SUCCESS(rv, rv); rv = statement->BindUTF8StringParameter(2, *mimeType); NS_ENSURE_SUCCESS(rv, rv); rv = statement->BindInt64Parameter(3, aExpiration); NS_ENSURE_SUCCESS(rv, rv); return statement->Execute(); }
nsresult nsFaviconService::DoSetAndLoadFaviconForPage(nsIURI* aPageURI, nsIURI* aFaviconURI, PRBool aForceReload) { nsCOMPtr<nsIURI> page(aPageURI); // don't load favicons when history is disabled nsNavHistory* history = nsNavHistory::GetHistoryService(); NS_ENSURE_TRUE(history, NS_ERROR_FAILURE); if (history->IsHistoryDisabled()) { // history is disabled - check to see if this favicon could be for a // bookmark nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService(); NS_ENSURE_TRUE(bookmarks, NS_ERROR_UNEXPECTED); nsCOMPtr<nsIURI> bookmarkURI; nsresult rv = bookmarks->GetBookmarkedURIFor(aPageURI, getter_AddRefs(bookmarkURI)); NS_ENSURE_SUCCESS(rv, rv); if (! bookmarkURI) { // page is not bookmarked, don't save favicon return NS_OK; } // page is bookmarked, set the URI to be the bookmark, the bookmark URI // might be different than our input URI if there was a redirect, so // always use the bookmark URI here to avoid setting the favicon for // non-bookmarked pages. page = bookmarkURI; } // check the failed favicon cache PRBool previouslyFailed; nsresult rv = IsFailedFavicon(aFaviconURI, &previouslyFailed); NS_ENSURE_SUCCESS(rv, rv); if (previouslyFailed) { if (aForceReload) RemoveFailedFavicon(aFaviconURI); // force reload clears from failed cache else return NS_OK; // ignore previously failed favicons } // filter out bad URLs PRBool canAdd; rv = history->CanAddURI(page, &canAdd); NS_ENSURE_SUCCESS(rv, rv); if (! canAdd) return NS_OK; // ignore favicons for this url // If have an image loaded in the main frame, that image will get set as its // own favicon. It would be nice to store a resampled version of the image, // but that's prohibitive for now. This workaround just refuses to save the // favicon in this case. PRBool pageEqualsFavicon; rv = page->Equals(aFaviconURI, &pageEqualsFavicon); NS_ENSURE_SUCCESS(rv, rv); if (pageEqualsFavicon) return NS_OK; // ignore error page favicons. nsCOMPtr<nsIURI> errorPageFavicon; rv = NS_NewURI(getter_AddRefs(errorPageFavicon), NS_LITERAL_CSTRING(FAVICON_ERRORPAGE_URL)); NS_ENSURE_SUCCESS(rv, rv); PRBool isErrorPage; rv = aFaviconURI->Equals(errorPageFavicon, &isErrorPage); NS_ENSURE_SUCCESS(rv, rv); if (isErrorPage) return NS_OK; // See if we have data and get the expiration time for this favicon. It might // be nice to say SetFaviconUrlForPageInternal here but we DON'T want to set // the favicon for the page unless we know we have it. For example, if I go // to random site x.com, the browser will still tell us that the favicon is // x.com/favicon.ico even if there is no such file. We don't want to pollute // our tables with this useless data. PRBool hasData = PR_FALSE; PRTime expiration = 0; { // scope for statement mozStorageStatementScoper scoper(mDBGetIconInfo); rv = BindStatementURI(mDBGetIconInfo, 0, aFaviconURI); NS_ENSURE_SUCCESS(rv, rv); PRBool hasMatch; rv = mDBGetIconInfo->ExecuteStep(&hasMatch); NS_ENSURE_SUCCESS(rv, rv); if (hasMatch) { PRInt32 dataSize; mDBGetIconInfo->GetInt32(1, &dataSize); hasData = dataSize > 0; mDBGetIconInfo->GetInt64(2, &expiration); } } // See if this favicon has expired yet. We don't want to waste time reloading // from the web or cache if we have a recent version. PRTime now = PR_Now(); if (hasData && now < expiration && ! aForceReload) { // data still valid, no need to reload // For page revisits (pretty common) we DON'T want to send out any // notifications if we've already set the favicon. These notifications will // cause parts of the UI to update and will be slow. This also saves us a // database write in these cases. nsCOMPtr<nsIURI> oldFavicon; PRBool faviconsEqual; if (NS_SUCCEEDED(GetFaviconForPage(page, getter_AddRefs(oldFavicon))) && NS_SUCCEEDED(aFaviconURI->Equals(oldFavicon, &faviconsEqual)) && faviconsEqual) return NS_OK; // already set // This will associate the favicon URL with the page. rv = SetFaviconUrlForPageInternal(page, aFaviconURI, &hasData, &expiration); NS_ENSURE_SUCCESS(rv, rv); SendFaviconNotifications(page, aFaviconURI); UpdateBookmarkRedirectFavicon(page, aFaviconURI); return NS_OK; } nsCOMPtr<nsIIOService> ioservice = do_GetIOService(&rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIChannel> channel; rv = ioservice->NewChannelFromURI(aFaviconURI, getter_AddRefs(channel)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIStreamListener> listener = new FaviconLoadListener(this, page, aFaviconURI, channel); NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY); nsCOMPtr<nsIInterfaceRequestor> listenerRequestor = do_QueryInterface(listener, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = channel->SetNotificationCallbacks(listenerRequestor); NS_ENSURE_SUCCESS(rv, rv); rv = channel->AsyncOpen(listener, nsnull); NS_ENSURE_SUCCESS(rv, rv); // DB will be update and observers will be notified when the data has // finished loading return NS_OK; }
nsresult nsFaviconService::SetFaviconUrlForPageInternal(nsIURI* aPageURI, nsIURI* aFaviconURI, PRBool* aHasData, PRTime* aExpiration) { nsresult rv; PRInt64 iconId = -1; mozStorageTransaction transaction(mDBConn, PR_FALSE); { mozStorageStatementScoper scoper(mDBGetIconInfo); rv = BindStatementURI(mDBGetIconInfo, 0, aFaviconURI); NS_ENSURE_SUCCESS(rv, rv); PRBool hasResult = PR_FALSE; if (NS_SUCCEEDED(mDBGetIconInfo->ExecuteStep(&hasResult)) && hasResult) { // We already have an entry for this icon, just get the stats rv = mDBGetIconInfo->GetInt64(0, &iconId); NS_ENSURE_SUCCESS(rv, rv); // see if this icon has data already PRInt32 dataSize; rv = mDBGetIconInfo->GetInt32(1, &dataSize); NS_ENSURE_SUCCESS(rv, rv); if (dataSize > 0) *aHasData = PR_TRUE; // expiration rv = mDBGetIconInfo->GetInt64(2, aExpiration); NS_ENSURE_SUCCESS(rv, rv); } } if (iconId == -1) { // We did not find any entry, so create a new one *aHasData = PR_FALSE; *aExpiration = 0; // not-binded params are automatically nullified by mozStorage mozStorageStatementScoper scoper(mDBInsertIcon); rv = BindStatementURI(mDBInsertIcon, 0, aFaviconURI); NS_ENSURE_SUCCESS(rv, rv); rv = mDBInsertIcon->Execute(); NS_ENSURE_SUCCESS(rv, rv); rv = mDBConn->GetLastInsertRowID(&iconId); NS_ENSURE_SUCCESS(rv, rv); } // now link our icon entry with the page nsNavHistory* historyService = nsNavHistory::GetHistoryService(); NS_ENSURE_TRUE(historyService, NS_ERROR_OUT_OF_MEMORY); PRInt64 pageId; rv = historyService->GetUrlIdFor(aPageURI, &pageId, PR_TRUE); NS_ENSURE_SUCCESS(rv, rv); mozStorageStatementScoper scoper(mDBSetPageFavicon); rv = mDBSetPageFavicon->BindInt64Parameter(0, pageId); NS_ENSURE_SUCCESS(rv, rv); rv = mDBSetPageFavicon->BindInt64Parameter(1, iconId); NS_ENSURE_SUCCESS(rv, rv); rv = mDBSetPageFavicon->Execute(); NS_ENSURE_SUCCESS(rv, rv); rv = transaction.Commit(); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }