summaryrefslogtreecommitdiffstats
path: root/chrome/browser/fav_icon_helper.cc
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/fav_icon_helper.cc
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/fav_icon_helper.cc')
-rw-r--r--chrome/browser/fav_icon_helper.cc290
1 files changed, 290 insertions, 0 deletions
diff --git a/chrome/browser/fav_icon_helper.cc b/chrome/browser/fav_icon_helper.cc
new file mode 100644
index 0000000..bef1efa
--- /dev/null
+++ b/chrome/browser/fav_icon_helper.cc
@@ -0,0 +1,290 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/browser/fav_icon_helper.h"
+
+#include "base/gfx/image_operations.h"
+#include "base/gfx/png_decoder.h"
+#include "base/gfx/png_encoder.h"
+#include "chrome/browser/navigation_entry.h"
+#include "chrome/browser/navigation_controller.h"
+#include "chrome/browser/tab_contents_delegate.h"
+#include "chrome/browser/render_view_host.h"
+#include "chrome/browser/web_contents.h"
+#include "chrome/common/gfx/favicon_size.h"
+
+FavIconHelper::FavIconHelper(WebContents* web_contents)
+ : web_contents_(web_contents),
+ got_fav_icon_url_(false),
+ got_fav_icon_from_history_(false),
+ fav_icon_expired_(false) {
+}
+
+void FavIconHelper::FetchFavIcon(const GURL& url) {
+ cancelable_consumer_.CancelAllRequests();
+
+ url_ = url;
+
+ fav_icon_expired_ = got_fav_icon_from_history_ = got_fav_icon_url_ = false;
+
+ // Request the favicon from the history service. In parallel to this the
+ // renderer is going to notify us (well webcontents) when the favicon url is
+ // available.
+ if (GetHistoryService()) {
+ GetHistoryService()->GetFavIconForURL(url_, &cancelable_consumer_,
+ NewCallback(this, &FavIconHelper::OnFavIconDataForInitialURL));
+ }
+}
+
+void FavIconHelper::SetFavIconURL(const GURL& icon_url) {
+ NavigationEntry* entry = GetEntry();
+ if (!entry)
+ return;
+
+ got_fav_icon_url_ = true;
+
+ if (!GetHistoryService())
+ return;
+
+ if (!fav_icon_expired_ && entry->IsValidFavIcon() &&
+ entry->GetFavIconURL() == icon_url) {
+ // We already have the icon, no need to proceed.
+ return;
+ }
+
+ entry->SetFavIconURL(icon_url);
+
+ if (got_fav_icon_from_history_)
+ DownloadFavIconOrAskHistory(entry);
+}
+
+Profile* FavIconHelper::profile() {
+ return web_contents_->profile();
+}
+
+HistoryService* FavIconHelper::GetHistoryService() {
+ return profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
+}
+
+void FavIconHelper::SetFavIcon(
+ int download_id,
+ const GURL& image_url,
+ const SkBitmap& image) {
+ DownloadRequests::iterator i = download_requests_.find(download_id);
+ if (i == download_requests_.end()) {
+ // Currently WebContents notifies us of ANY downloads so that it is
+ // possible to get here.
+ return;
+ }
+
+ const SkBitmap& sized_image =
+ (image.width() == kFavIconSize && image.height() == kFavIconSize)
+ ? image : ConvertToFavIconSize(image);
+
+ if (GetHistoryService() && !profile()->IsOffTheRecord()) {
+ std::vector<unsigned char> image_data;
+ SkAutoLockPixels icon_lock(sized_image);
+ PNGEncoder::Encode(
+ reinterpret_cast<unsigned char*>(sized_image.getPixels()),
+ PNGEncoder::FORMAT_BGRA, sized_image.width(),
+ sized_image.height(), sized_image.width()* 4, false,
+ &image_data);
+ GetHistoryService()->SetFavIcon(i->second.url, i->second.fav_icon_url,
+ image_data);
+ }
+
+ if (i->second.url == url_) {
+ NavigationEntry* entry = GetEntry();
+ if (entry)
+ UpdateFavIcon(entry, sized_image);
+ }
+
+ download_requests_.erase(i);
+}
+
+void FavIconHelper::FavIconDownloadFailed(int download_id) {
+ DownloadRequests::iterator i = download_requests_.find(download_id);
+ if (i != download_requests_.end())
+ download_requests_.erase(i);
+}
+
+void FavIconHelper::UpdateFavIcon(NavigationEntry* entry,
+ const std::vector<unsigned char>& data) {
+ SkBitmap image;
+ PNGDecoder::Decode(&data, &image);
+ UpdateFavIcon(entry, image);
+}
+
+void FavIconHelper::UpdateFavIcon(NavigationEntry* entry,
+ const SkBitmap& image) {
+ // No matter what happens, we need to mark the favicon as being set.
+ entry->SetValidFavIcon(true);
+
+ if (image.empty())
+ return;
+
+ entry->SetFavIcon(image);
+ if (web_contents_->delegate()) {
+ web_contents_->delegate()->NavigationStateChanged(
+ web_contents_, TabContents::INVALIDATE_FAVICON);
+ }
+}
+
+NavigationEntry* FavIconHelper::GetEntry() {
+ NavigationEntry* entry = web_contents_->controller()->GetActiveEntry();
+ if (entry && entry->GetURL() == url_ &&
+ web_contents_->IsActiveEntry(entry->GetPageID())) {
+ return entry;
+ }
+ // If the URL has changed out from under us (as will happen with redirects)
+ // return NULL.
+ return NULL;
+}
+
+void FavIconHelper::OnFavIconDataForInitialURL(
+ HistoryService::Handle handle,
+ bool know_favicon,
+ scoped_refptr<RefCountedBytes> data,
+ bool expired,
+ GURL icon_url) {
+ NavigationEntry* entry = GetEntry();
+ if (!entry)
+ return;
+
+ got_fav_icon_from_history_ = true;
+
+ fav_icon_expired_ = (know_favicon && expired);
+
+ if (know_favicon && !entry->IsValidFavIcon() &&
+ (!got_fav_icon_url_ || entry->GetFavIconURL() == icon_url)) {
+ // The db knows the favicon (although it may be out of date) and the entry
+ // doesn't have an icon. Set the favicon now, and if the favicon turns out
+ // to be expired (or the wrong url) we'll fetch later on. This way the
+ // user doesn't see a flash of the default favicon.
+ entry->SetFavIconURL(icon_url);
+ if (data && !data->data.empty())
+ UpdateFavIcon(entry, data->data);
+ entry->SetValidFavIcon(true);
+ }
+
+ if (know_favicon && !expired) {
+ if (got_fav_icon_url_ && entry->GetFavIconURL() != icon_url) {
+ // Mapping in the database is wrong. DownloadFavIconOrAskHistory will
+ // update the mapping for this url and download the favicon if we don't
+ // already have it.
+ DownloadFavIconOrAskHistory(entry);
+ }
+ } else if (got_fav_icon_url_) {
+ // We know the official url for the favicon, by either don't have the
+ // favicon or its expired. Continue on to DownloadFavIconOrAskHistory to
+ // either download or check history again.
+ DownloadFavIconOrAskHistory(entry);
+ } // else we haven't got the icon url. When we get it we'll ask the
+ // renderer to download the icon.
+}
+
+void FavIconHelper::DownloadFavIconOrAskHistory(NavigationEntry* entry) {
+ DCHECK(entry); // We should only get here if entry is valid.
+ if (fav_icon_expired_) {
+ // We have the mapping, but the favicon is out of date. Download it now.
+ ScheduleDownload(entry);
+ } else if (GetHistoryService()) {
+ // We don't know the favicon, but we may have previously downloaded the
+ // favicon for another page that shares the same favicon. Ask for the
+ // favicon given the favicon URL.
+ if (profile()->IsOffTheRecord()) {
+ GetHistoryService()->GetFavIcon(
+ entry->GetFavIconURL(),
+ &cancelable_consumer_,
+ NewCallback(this, &FavIconHelper::OnFavIconData));
+ } else {
+ // Ask the history service for the icon. This does two things:
+ // 1. Attempts to fetch the favicon data from the database.
+ // 2. If the favicon exists in the database, this updates the database to
+ // include the mapping between the page url and the favicon url.
+ // This is asynchronous. The history service will call back when done.
+ // Issue the request and associate the current page ID with it.
+ GetHistoryService()->UpdateFavIconMappingAndFetch(
+ entry->GetURL(),
+ entry->GetFavIconURL(), &cancelable_consumer_,
+ NewCallback(this, &FavIconHelper::OnFavIconData));
+ }
+ }
+}
+
+void FavIconHelper::OnFavIconData(
+ HistoryService::Handle handle,
+ bool know_favicon,
+ scoped_refptr<RefCountedBytes> data,
+ bool expired,
+ GURL icon_url) {
+ NavigationEntry* entry = GetEntry();
+ if (!entry)
+ return;
+
+ // No need to update the favicon url. By the time we get here
+ // UpdateFavIconURL will have set the favicon url.
+
+ if (know_favicon && data && !data->data.empty()) {
+ // There is a favicon, set it now. If expired we'll download the current
+ // one again, but at least the user will get some icon instead of the
+ // default and most likely the current one is fine anyway.
+ UpdateFavIcon(entry, data->data);
+ }
+
+ if (!know_favicon || expired) {
+ // We don't know the favicon, or it is out of date. Request the current one.
+ ScheduleDownload(entry);
+ }
+}
+
+void FavIconHelper::ScheduleDownload(NavigationEntry* entry) {
+ const int download_id = web_contents_->render_view_host()->DownloadImage(
+ entry->GetFavIconURL(), kFavIconSize);
+ if (!download_id) {
+ // Download request failed.
+ return;
+ }
+ // Download ids should be unique.
+ DCHECK(download_requests_.find(download_id) == download_requests_.end());
+ download_requests_[download_id] =
+ DownloadRequest(entry->GetURL(), entry->GetFavIconURL());
+}
+
+SkBitmap FavIconHelper::ConvertToFavIconSize(const SkBitmap& image) {
+ int width = image.width();
+ int height = image.height();
+ if (width > 0 && height > 0) {
+ calc_favicon_target_size(&width, &height);
+ return gfx::ImageOperations::Resize(
+ image, gfx::ImageOperations::RESIZE_LANCZOS3,
+ gfx::Size(width, height));
+ }
+ return image;
+}