summaryrefslogtreecommitdiffstats
path: root/chrome/browser/favicon
diff options
context:
space:
mode:
authoravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-28 22:19:14 +0000
committeravi@chromium.org <avi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-28 22:19:14 +0000
commitee2ed42c72935932a756dedfe797d96bd0205e31 (patch)
treeaee48705aeabd69a6b7c1b08510c3309484b1561 /chrome/browser/favicon
parentad9a072a78fea6d59e142716ca4104687490bfc6 (diff)
downloadchromium_src-ee2ed42c72935932a756dedfe797d96bd0205e31.zip
chromium_src-ee2ed42c72935932a756dedfe797d96bd0205e31.tar.gz
chromium_src-ee2ed42c72935932a756dedfe797d96bd0205e31.tar.bz2
Favicon file shuffling.
Moves them to their own directory, renames the Helper to TabHelper in prep for moving it to TabContentsWrapper. BUG=71097 TEST=none Review URL: http://codereview.chromium.org/6902125 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@83425 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/favicon')
-rw-r--r--chrome/browser/favicon/favicon_handler.cc448
-rw-r--r--chrome/browser/favicon/favicon_handler.h261
-rw-r--r--chrome/browser/favicon/favicon_handler_unittest.cc768
-rw-r--r--chrome/browser/favicon/favicon_service.cc97
-rw-r--r--chrome/browser/favicon/favicon_service.h106
-rw-r--r--chrome/browser/favicon/favicon_tab_helper.cc67
-rw-r--r--chrome/browser/favicon/favicon_tab_helper.h76
7 files changed, 1823 insertions, 0 deletions
diff --git a/chrome/browser/favicon/favicon_handler.cc b/chrome/browser/favicon/favicon_handler.cc
new file mode 100644
index 0000000..66d2b47
--- /dev/null
+++ b/chrome/browser/favicon/favicon_handler.cc
@@ -0,0 +1,448 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/favicon/favicon_handler.h"
+
+#include "build/build_config.h"
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted_memory.h"
+#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/icon_messages.h"
+#include "content/browser/renderer_host/render_view_host.h"
+#include "content/browser/tab_contents/navigation_controller.h"
+#include "content/browser/tab_contents/navigation_entry.h"
+#include "content/browser/tab_contents/tab_contents_delegate.h"
+#include "content/browser/tab_contents/tab_contents.h"
+#include "skia/ext/image_operations.h"
+#include "ui/gfx/codec/png_codec.h"
+
+namespace {
+
+// Returns history::IconType the given icon_type corresponds to.
+history::IconType ToHistoryIconType(FaviconURL::IconType icon_type) {
+ switch (icon_type) {
+ case FaviconURL::FAVICON:
+ return history::FAVICON;
+ case FaviconURL::TOUCH_ICON:
+ return history::TOUCH_ICON;
+ case FaviconURL::TOUCH_PRECOMPOSED_ICON:
+ return history::TOUCH_PRECOMPOSED_ICON;
+ case FaviconURL::INVALID_ICON:
+ return history::INVALID_ICON;
+ }
+ NOTREACHED();
+ // Shouldn't reach here, just make compiler happy.
+ return history::INVALID_ICON;
+}
+
+bool DoUrlAndIconMatch(const FaviconURL& favicon_url,
+ const GURL& url,
+ history::IconType icon_type) {
+ return favicon_url.icon_url == url &&
+ favicon_url.icon_type == static_cast<FaviconURL::IconType>(icon_type);
+}
+
+} // namespace
+
+FaviconHandler::DownloadRequest::DownloadRequest()
+ : callback(NULL),
+ icon_type(history::INVALID_ICON) {
+}
+
+FaviconHandler::DownloadRequest::DownloadRequest(
+ const GURL& url,
+ const GURL& image_url,
+ FaviconTabHelper::ImageDownloadCallback* callback,
+ history::IconType icon_type)
+ : url(url),
+ image_url(image_url),
+ callback(callback),
+ icon_type(icon_type) {
+}
+
+FaviconHandler::FaviconHandler(TabContents* tab_contents, Type icon_type)
+ : got_favicon_from_history_(false),
+ favicon_expired_(false),
+ icon_types_(icon_type == FAVICON ? history::FAVICON :
+ history::TOUCH_ICON | history::TOUCH_PRECOMPOSED_ICON),
+ current_url_index_(0),
+ tab_contents_(tab_contents) {
+}
+
+FaviconHandler::~FaviconHandler() {
+ SkBitmap empty_image;
+
+ // Call pending download callbacks with error to allow caller to clean up.
+ for (DownloadRequests::iterator i = download_requests_.begin();
+ i != download_requests_.end(); ++i) {
+ if (i->second.callback) {
+ i->second.callback->Run(i->first, true, empty_image);
+ }
+ }
+}
+
+void FaviconHandler::FetchFavicon(const GURL& url) {
+ cancelable_consumer_.CancelAllRequests();
+
+ url_ = url;
+
+ favicon_expired_ = got_favicon_from_history_ = false;
+ current_url_index_ = 0;
+ urls_.clear();
+
+ // Request the favicon from the history service. In parallel to this the
+ // renderer is going to notify us (well TabContents) when the favicon url is
+ // available.
+ if (GetFaviconService()) {
+ GetFaviconForURL(url_, icon_types_, &cancelable_consumer_,
+ NewCallback(this, &FaviconHandler::OnFaviconDataForInitialURL));
+ }
+}
+
+int FaviconHandler::DownloadImage(
+ const GURL& image_url,
+ int image_size,
+ history::IconType icon_type,
+ FaviconTabHelper::ImageDownloadCallback* callback) {
+ DCHECK(callback); // Must provide a callback.
+ return ScheduleDownload(GURL(), image_url, image_size, icon_type, callback);
+}
+
+FaviconService* FaviconHandler::GetFaviconService() {
+ return tab_contents()->profile()->GetFaviconService(Profile::EXPLICIT_ACCESS);
+}
+
+void FaviconHandler::SetFavicon(
+ const GURL& url,
+ const GURL& image_url,
+ const SkBitmap& image,
+ history::IconType icon_type) {
+ const SkBitmap& sized_image = (preferred_icon_size() == 0 ||
+ (preferred_icon_size() == image.width() &&
+ preferred_icon_size() == image.height())) ?
+ image : ConvertToFaviconSize(image);
+
+ if (GetFaviconService() && ShouldSaveFavicon(url)) {
+ std::vector<unsigned char> image_data;
+ gfx::PNGCodec::EncodeBGRASkBitmap(sized_image, false, &image_data);
+ SetHistoryFavicon(url, image_url, image_data, icon_type);
+ }
+
+ if (url == url_ && icon_type == history::FAVICON) {
+ NavigationEntry* entry = GetEntry();
+ if (entry)
+ UpdateFavicon(entry, sized_image);
+ }
+}
+
+void FaviconHandler::UpdateFavicon(NavigationEntry* entry,
+ scoped_refptr<RefCountedMemory> data) {
+ SkBitmap image;
+ gfx::PNGCodec::Decode(data->front(), data->size(), &image);
+ UpdateFavicon(entry, image);
+}
+
+void FaviconHandler::UpdateFavicon(NavigationEntry* entry,
+ const SkBitmap& image) {
+ // No matter what happens, we need to mark the favicon as being set.
+ entry->favicon().set_is_valid(true);
+
+ if (image.empty())
+ return;
+
+ entry->favicon().set_bitmap(image);
+ tab_contents()->NotifyNavigationStateChanged(TabContents::INVALIDATE_TAB);
+}
+
+void FaviconHandler::OnUpdateFaviconURL(
+ int32 page_id,
+ const std::vector<FaviconURL>& candidates) {
+ NavigationEntry* entry = GetEntry();
+ if (!entry)
+ return;
+
+ bool got_favicon_url_update = false;
+ for (std::vector<FaviconURL>::const_iterator i = candidates.begin();
+ i != candidates.end(); ++i) {
+ if (!i->icon_url.is_empty() && (i->icon_type & icon_types_)) {
+ if (!got_favicon_url_update) {
+ got_favicon_url_update = true;
+ urls_.clear();
+ current_url_index_ = 0;
+ }
+ urls_.push_back(*i);
+ }
+ }
+
+ // TODO(davemoore) Should clear on empty url. Currently we ignore it.
+ // This appears to be what FF does as well.
+ // No URL was added.
+ if (!got_favicon_url_update)
+ return;
+
+ if (!GetFaviconService())
+ return;
+
+ // For FAVICON.
+ if (current_candidate()->icon_type == FaviconURL::FAVICON) {
+ if (!favicon_expired_ && entry->favicon().is_valid() &&
+ DoUrlAndIconMatch(*current_candidate(), entry->favicon().url(),
+ history::FAVICON))
+ return;
+
+ entry->favicon().set_url(current_candidate()->icon_url);
+ } else if (!favicon_expired_ && got_favicon_from_history_ &&
+ history_icon_.is_valid() &&
+ DoUrlAndIconMatch(
+ *current_candidate(),
+ history_icon_.icon_url, history_icon_.icon_type)) {
+ return;
+ }
+
+ if (got_favicon_from_history_)
+ DownloadFaviconOrAskHistory(entry->url(), current_candidate()->icon_url,
+ ToHistoryIconType(current_candidate()->icon_type));
+}
+
+void FaviconHandler::OnDidDownloadFavicon(int id,
+ const GURL& image_url,
+ bool errored,
+ const SkBitmap& image) {
+ DownloadRequests::iterator i = download_requests_.find(id);
+ if (i == download_requests_.end()) {
+ // Currently TabContents notifies us of ANY downloads so that it is
+ // possible to get here.
+ return;
+ }
+
+ if (i->second.callback) {
+ i->second.callback->Run(id, errored, image);
+ } else if (current_candidate() &&
+ DoUrlAndIconMatch(*current_candidate(), image_url,
+ i->second.icon_type)) {
+ // The downloaded icon is still valid when there is no FaviconURL update
+ // during the downloading.
+ if (!errored) {
+ SetFavicon(i->second.url, image_url, image, i->second.icon_type);
+ } else if (GetEntry() && ++current_url_index_ < urls_.size()) {
+ // Copies all candidate except first one and notifies the FaviconHandler,
+ // so the next candidate can be processed.
+ std::vector<FaviconURL> new_candidates(++urls_.begin(), urls_.end());
+ OnUpdateFaviconURL(0, new_candidates);
+ }
+ }
+ download_requests_.erase(i);
+}
+
+NavigationEntry* FaviconHandler::GetEntry() {
+ NavigationEntry* entry = tab_contents()->controller().GetActiveEntry();
+ if (entry && entry->url() == url_ &&
+ tab_contents()->IsActiveEntry(entry->page_id())) {
+ return entry;
+ }
+ // If the URL has changed out from under us (as will happen with redirects)
+ // return NULL.
+ return NULL;
+}
+
+int FaviconHandler::DownloadFavicon(const GURL& image_url, int image_size) {
+ if (!image_url.is_valid()) {
+ NOTREACHED();
+ return 0;
+ }
+ static int next_id = 1;
+ int id = next_id++;
+ RenderViewHost* host = tab_contents()->render_view_host();
+ host->Send(new IconMsg_DownloadFavicon(
+ host->routing_id(), id, image_url, image_size));
+ return id;
+}
+
+void FaviconHandler::UpdateFaviconMappingAndFetch(
+ const GURL& page_url,
+ const GURL& icon_url,
+ history::IconType icon_type,
+ CancelableRequestConsumerBase* consumer,
+ FaviconService::FaviconDataCallback* callback) {
+ GetFaviconService()->UpdateFaviconMappingAndFetch(page_url, icon_url,
+ icon_type, consumer, callback);
+}
+
+void FaviconHandler::GetFavicon(
+ const GURL& icon_url,
+ history::IconType icon_type,
+ CancelableRequestConsumerBase* consumer,
+ FaviconService::FaviconDataCallback* callback) {
+ GetFaviconService()->GetFavicon(icon_url, icon_type, consumer, callback);
+}
+
+void FaviconHandler::GetFaviconForURL(
+ const GURL& page_url,
+ int icon_types,
+ CancelableRequestConsumerBase* consumer,
+ FaviconService::FaviconDataCallback* callback) {
+ GetFaviconService()->GetFaviconForURL(page_url, icon_types, consumer,
+ callback);
+}
+
+void FaviconHandler::SetHistoryFavicon(
+ const GURL& page_url,
+ const GURL& icon_url,
+ const std::vector<unsigned char>& image_data,
+ history::IconType icon_type) {
+ GetFaviconService()->SetFavicon(page_url, icon_url, image_data, icon_type);
+}
+
+bool FaviconHandler::ShouldSaveFavicon(const GURL& url) {
+ if (!tab_contents()->profile()->IsOffTheRecord())
+ return true;
+
+ // Otherwise store the favicon if the page is bookmarked.
+ BookmarkModel* bookmark_model = tab_contents()->profile()->GetBookmarkModel();
+ return bookmark_model && bookmark_model->IsBookmarked(url);
+}
+
+void FaviconHandler::OnFaviconDataForInitialURL(
+ FaviconService::Handle handle,
+ history::FaviconData favicon) {
+ NavigationEntry* entry = GetEntry();
+ if (!entry)
+ return;
+
+ got_favicon_from_history_ = true;
+ history_icon_ = favicon;
+
+ favicon_expired_ = (favicon.known_icon && favicon.expired);
+
+ if (favicon.known_icon && favicon.icon_type == history::FAVICON &&
+ !entry->favicon().is_valid() &&
+ (!current_candidate() ||
+ DoUrlAndIconMatch(
+ *current_candidate(), favicon.icon_url, favicon.icon_type))) {
+ // 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->favicon().set_url(favicon.icon_url);
+ if (favicon.is_valid())
+ UpdateFavicon(entry, favicon.image_data);
+ entry->favicon().set_is_valid(true);
+ }
+
+ if (favicon.known_icon && !favicon.expired) {
+ if (current_candidate() &&
+ !DoUrlAndIconMatch(
+ *current_candidate(), favicon.icon_url, favicon.icon_type)) {
+ // 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->url(), current_candidate()->icon_url,
+ static_cast<history::IconType>(current_candidate()->icon_type));
+ }
+ } else if (current_candidate()) {
+ // 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->url(), current_candidate()->icon_url,
+ ToHistoryIconType(current_candidate()->icon_type));
+ }
+ // else we haven't got the icon url. When we get it we'll ask the
+ // renderer to download the icon.
+}
+
+void FaviconHandler::DownloadFaviconOrAskHistory(
+ const GURL& page_url,
+ const GURL& icon_url,
+ history::IconType icon_type) {
+ if (favicon_expired_) {
+ // We have the mapping, but the favicon is out of date. Download it now.
+ ScheduleDownload(page_url, icon_url, preferred_icon_size(), icon_type,
+ NULL);
+ } else if (GetFaviconService()) {
+ // 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 (tab_contents()->profile()->IsOffTheRecord()) {
+ GetFavicon(icon_url, icon_type, &cancelable_consumer_,
+ NewCallback(this, &FaviconHandler::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.
+ UpdateFaviconMappingAndFetch(page_url, icon_url, icon_type,
+ &cancelable_consumer_,
+ NewCallback(this, &FaviconHandler::OnFaviconData));
+ }
+ }
+}
+
+void FaviconHandler::OnFaviconData(FaviconService::Handle handle,
+ history::FaviconData favicon) {
+ 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 (favicon.icon_type == history::FAVICON) {
+ if (favicon.is_valid()) {
+ // 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, favicon.image_data);
+ }
+ if (!favicon.known_icon || favicon.expired) {
+ // We don't know the favicon, or it is out of date. Request the current
+ // one.
+ ScheduleDownload(entry->url(), entry->favicon().url(),
+ preferred_icon_size(),
+ history::FAVICON, NULL);
+ }
+ } else if (current_candidate() && (!favicon.known_icon || favicon.expired ||
+ !(DoUrlAndIconMatch(
+ *current_candidate(), favicon.icon_url, favicon.icon_type)))) {
+ // We don't know the favicon, it is out of date or its type is not same as
+ // one got from page. Request the current one.
+ ScheduleDownload(entry->url(), current_candidate()->icon_url,
+ preferred_icon_size(),
+ ToHistoryIconType(current_candidate()->icon_type), NULL);
+ }
+ history_icon_ = favicon;
+}
+
+int FaviconHandler::ScheduleDownload(
+ const GURL& url,
+ const GURL& image_url,
+ int image_size,
+ history::IconType icon_type,
+ FaviconTabHelper::ImageDownloadCallback* callback) {
+ const int download_id = DownloadFavicon(image_url, image_size);
+ if (download_id) {
+ // Download ids should be unique.
+ DCHECK(download_requests_.find(download_id) == download_requests_.end());
+ download_requests_[download_id] =
+ DownloadRequest(url, image_url, callback, icon_type);
+ }
+
+ return download_id;
+}
+
+SkBitmap FaviconHandler::ConvertToFaviconSize(const SkBitmap& image) {
+ int width = image.width();
+ int height = image.height();
+ if (width > 0 && height > 0) {
+ calc_favicon_target_size(&width, &height);
+ return skia::ImageOperations::Resize(
+ image, skia::ImageOperations::RESIZE_LANCZOS3,
+ width, height);
+ }
+ return image;
+}
diff --git a/chrome/browser/favicon/favicon_handler.h b/chrome/browser/favicon/favicon_handler.h
new file mode 100644
index 0000000..8cc26be
--- /dev/null
+++ b/chrome/browser/favicon/favicon_handler.h
@@ -0,0 +1,261 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_FAVICON_FAVICON_HANDLER_H_
+#define CHROME_BROWSER_FAVICON_FAVICON_HANDLER_H_
+#pragma once
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "chrome/browser/favicon/favicon_service.h"
+#include "chrome/browser/favicon/favicon_tab_helper.h"
+#include "chrome/common/favicon_url.h"
+#include "chrome/common/ref_counted_util.h"
+#include "content/browser/cancelable_request.h"
+#include "googleurl/src/gurl.h"
+#include "ui/gfx/favicon_size.h"
+
+class NavigationEntry;
+class Profile;
+class RefCountedMemory;
+class SkBitmap;
+class TabContents;
+
+// FaviconHandler works with FaviconTabHelper to fetch the specific type of
+// favicon.
+//
+// FetchFavicon requests the favicon from the favicon service which in turn
+// requests the favicon from the history database. At this point
+// we only know the URL of the page, and not necessarily the url of the
+// favicon. To ensure we handle reloading stale favicons as well as
+// reloading a favicon on page reload we always request the favicon from
+// history regardless of whether the NavigationEntry has a favicon.
+//
+// After the navigation two types of events are delivered (which is
+// first depends upon who is faster): notification from the history
+// db on our request for the favicon (OnFaviconDataForInitialURL),
+// or a message from the renderer giving us the URL of the favicon for
+// the page (SetFaviconURL).
+// . If the history db has a valid up to date favicon for the page, we update
+// the NavigationEntry and use the favicon.
+// . When we receive the favicon url if it matches that of the NavigationEntry
+// and the NavigationEntry's favicon is set, we do nothing (everything is
+// ok).
+// . On the other hand if the database does not know the favicon for url, or
+// the favicon is out date, or the URL from the renderer does not match that
+// NavigationEntry we proceed to DownloadFaviconOrAskHistory. Before we
+// invoke DownloadFaviconOrAskHistory we wait until we've received both
+// the favicon url and the callback from history. We wait to ensure we
+// truly know both the favicon url and the state of the database.
+//
+// DownloadFaviconOrAskHistory does the following:
+// . If we have a valid favicon, but it is expired we ask the renderer to
+// download the favicon.
+// . Otherwise we ask the history database to update the mapping from
+// page url to favicon url and call us back with the favicon. Remember, it is
+// possible for the db to already have the favicon, just not the mapping
+// between page to favicon url. The callback for this is OnFaviconData.
+//
+// OnFaviconData either updates the favicon of the NavigationEntry (if the
+// db knew about the favicon), or requests the renderer to download the
+// favicon.
+//
+// When the renderer downloads the favicon SetFaviconImageData is invoked,
+// at which point we update the favicon of the NavigationEntry and notify
+// the database to save the favicon.
+
+class FaviconHandler {
+ public:
+ enum Type {
+ FAVICON,
+ TOUCH,
+ };
+
+ FaviconHandler(TabContents* tab_contents, Type icon_type);
+ virtual ~FaviconHandler();
+
+ // Initiates loading the favicon for the specified url.
+ void FetchFavicon(const GURL& url);
+
+ // Initiates loading an image from given |image_url|. Returns a download id
+ // for caller to track the request. When download completes, |callback| is
+ // called with the three params: the download_id, a boolean flag to indicate
+ // whether the download succeeds and a SkBitmap as the downloaded image.
+ // Note that |image_size| is a hint for images with multiple sizes. The
+ // downloaded image is not resized to the given image_size. If 0 is passed,
+ // the first frame of the image is returned.
+ int DownloadImage(const GURL& image_url,
+ int image_size,
+ history::IconType icon_type,
+ FaviconTabHelper::ImageDownloadCallback* callback);
+
+ // Message Handler. Must be public, because also called from
+ // PrerenderContents.
+ void OnUpdateFaviconURL(int32 page_id,
+ const std::vector<FaviconURL>& candidates);
+
+ void OnDidDownloadFavicon(int id,
+ const GURL& image_url,
+ bool errored,
+ const SkBitmap& image);
+
+ protected:
+ // These virtual methods make FaviconHandler testable and are overridden by
+ // TestFaviconHandler.
+
+ // Return the NavigationEntry for the active entry, or NULL if the active
+ // entries URL does not match that of the URL last passed to FetchFavicon.
+ virtual NavigationEntry* GetEntry();
+
+ // Asks the render to download favicon, returns the request id.
+ virtual int DownloadFavicon(const GURL& image_url, int image_size);
+
+ // Ask the favicon from history
+ virtual void UpdateFaviconMappingAndFetch(
+ const GURL& page_url,
+ const GURL& icon_url,
+ history::IconType icon_type,
+ CancelableRequestConsumerBase* consumer,
+ FaviconService::FaviconDataCallback* callback);
+
+ virtual void GetFavicon(
+ const GURL& icon_url,
+ history::IconType icon_type,
+ CancelableRequestConsumerBase* consumer,
+ FaviconService::FaviconDataCallback* callback);
+
+ virtual void GetFaviconForURL(
+ const GURL& page_url,
+ int icon_types,
+ CancelableRequestConsumerBase* consumer,
+ FaviconService::FaviconDataCallback* callback);
+
+ virtual void SetHistoryFavicon(const GURL& page_url,
+ const GURL& icon_url,
+ const std::vector<unsigned char>& image_data,
+ history::IconType icon_type);
+
+ virtual FaviconService* GetFaviconService();
+
+ // Returns true if the favicon should be saved.
+ virtual bool ShouldSaveFavicon(const GURL& url);
+
+ private:
+ friend class TestFaviconHandler; // For testing
+
+ struct DownloadRequest {
+ DownloadRequest();
+
+ DownloadRequest(const GURL& url,
+ const GURL& image_url,
+ FaviconTabHelper::ImageDownloadCallback* callback,
+ history::IconType icon_type);
+
+ GURL url;
+ GURL image_url;
+ FaviconTabHelper::ImageDownloadCallback* callback;
+ history::IconType icon_type;
+ };
+
+ // See description above class for details.
+ void OnFaviconDataForInitialURL(FaviconService::Handle handle,
+ history::FaviconData favicon);
+
+ // If the favicon has expired, asks the renderer to download the favicon.
+ // Otherwise asks history to update the mapping between page url and icon
+ // url with a callback to OnFaviconData when done.
+ void DownloadFaviconOrAskHistory(const GURL& page_url,
+ const GURL& icon_url,
+ history::IconType icon_type);
+
+ // See description above class for details.
+ void OnFaviconData(FaviconService::Handle handle,
+ history::FaviconData favicon);
+
+ // Schedules a download for the specified entry. This adds the request to
+ // download_requests_.
+ int ScheduleDownload(const GURL& url,
+ const GURL& image_url,
+ int image_size,
+ history::IconType icon_type,
+ FaviconTabHelper::ImageDownloadCallback* callback);
+
+ // Sets the image data for the favicon. This is invoked asynchronously after
+ // we request the TabContents to download the favicon.
+ void SetFavicon(const GURL& url,
+ const GURL& icon_url,
+ const SkBitmap& image,
+ history::IconType icon_type);
+
+ // Converts the FAVICON's image data to an SkBitmap and sets it on the
+ // NavigationEntry.
+ // If the TabContents has a delegate, it is notified of the new favicon
+ // (INVALIDATE_FAVICON).
+ void UpdateFavicon(NavigationEntry* entry,
+ scoped_refptr<RefCountedMemory> data);
+ void UpdateFavicon(NavigationEntry* entry, const SkBitmap& image);
+
+ // Scales the image such that either the width and/or height is 16 pixels
+ // wide. Does nothing if the image is empty.
+ SkBitmap ConvertToFaviconSize(const SkBitmap& image);
+
+ void FetchFaviconInternal();
+
+ // Return the current candidate if any.
+ FaviconURL* current_candidate() {
+ return (urls_.size() > current_url_index_) ?
+ &urls_[current_url_index_] : NULL;
+ }
+
+ // Returns the preferred_icon_size according icon_types_, 0 means no
+ // preference.
+ int preferred_icon_size() {
+ return icon_types_ == history::FAVICON ? kFaviconSize : 0;
+ }
+
+ TabContents* tab_contents() {
+ return tab_contents_;
+ }
+
+ // Used for history requests.
+ CancelableRequestConsumer cancelable_consumer_;
+
+ // URL of the page we're requesting the favicon for.
+ GURL url_;
+
+ // Whether we got the initial response for the favicon back from the renderer.
+ // See "Favicon Details" in tab_contents.cc for more details.
+ bool got_favicon_from_history_;
+
+ // Whether the favicon is out of date. If true, it means history knows about
+ // the favicon, but we need to download the favicon because the icon has
+ // expired.
+ // See "Favicon Details" in tab_contents.cc for more details.
+ bool favicon_expired_;
+
+ // Requests to the renderer to download favicons.
+ typedef std::map<int, DownloadRequest> DownloadRequests;
+ DownloadRequests download_requests_;
+
+ // The combination of the supported icon types.
+ const int icon_types_;
+
+ // The prioritized favicon candidates from the page back from the renderer.
+ std::vector<FaviconURL> urls_;
+
+ // The current candidate's index in urls_.
+ size_t current_url_index_;
+
+ // The FaviconData from history.
+ history::FaviconData history_icon_;
+
+ TabContents* tab_contents_;
+
+ DISALLOW_COPY_AND_ASSIGN(FaviconHandler);
+};
+
+#endif // CHROME_BROWSER_FAVICON_FAVICON_HANDLER_H_
diff --git a/chrome/browser/favicon/favicon_handler_unittest.cc b/chrome/browser/favicon/favicon_handler_unittest.cc
new file mode 100644
index 0000000..dc26ef5
--- /dev/null
+++ b/chrome/browser/favicon/favicon_handler_unittest.cc
@@ -0,0 +1,768 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/favicon/favicon_handler.h"
+#include "content/browser/renderer_host/test_render_view_host.h"
+#include "content/browser/tab_contents/navigation_entry.h"
+#include "content/browser/tab_contents/test_tab_contents.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/favicon_size.h"
+
+class TestFaviconHandler;
+
+namespace {
+
+// Fill the given bmp with valid png data.
+void FillDataToBitmap(int w, int h, SkBitmap* bmp) {
+ bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h);
+ bmp->allocPixels();
+
+ unsigned char* src_data =
+ reinterpret_cast<unsigned char*>(bmp->getAddr32(0, 0));
+ for (int i = 0; i < w * h; i++) {
+ src_data[i * 4 + 0] = static_cast<unsigned char>(i % 255);
+ src_data[i * 4 + 1] = static_cast<unsigned char>(i % 255);
+ src_data[i * 4 + 2] = static_cast<unsigned char>(i % 255);
+ src_data[i * 4 + 3] = static_cast<unsigned char>(i % 255);
+ }
+}
+
+// Fill the given data buffer with valid png data.
+void FillBitmap(int w, int h, std::vector<unsigned char>* output) {
+ SkBitmap bitmap;
+ FillDataToBitmap(w, h, &bitmap);
+ gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, output);
+}
+
+// This class is used to save the download request for verifying with test case.
+// It also will be used to invoke the onDidDownload callback.
+class DownloadHandler {
+ public:
+ DownloadHandler(int download_id,
+ const GURL& image_url,
+ int image_size,
+ TestFaviconHandler* favicon_helper)
+ : image_url_(image_url),
+ image_size_(image_size),
+ failed_(false),
+ download_id_(download_id),
+ favicon_helper_(favicon_helper) {
+ FillDataToBitmap(16, 16, &bitmap_);
+ }
+
+ virtual ~DownloadHandler() {
+ }
+
+ static void UpdateFaviconURL(FaviconHandler* helper,
+ const std::vector<FaviconURL> urls);
+
+ void InvokeCallback();
+
+ void UpdateFaviconURL(const std::vector<FaviconURL> urls);
+
+ const GURL image_url_;
+ const int image_size_;
+
+ // Simulates download failed or not.
+ bool failed_;
+
+ private:
+ // Identified the specific download, will also be passed in
+ // OnDidDownloadFavicon callback.
+ int download_id_;
+ TestFaviconHandler* favicon_helper_;
+ SkBitmap bitmap_;
+
+ DISALLOW_COPY_AND_ASSIGN(DownloadHandler);
+};
+
+// This class is used to save the history request for verifying with test case.
+// It also will be used to simulate the history response.
+class HistoryRequestHandler {
+ public:
+ HistoryRequestHandler(const GURL& page_url,
+ const GURL& icon_url,
+ int icon_type,
+ FaviconService::FaviconDataCallback* callback)
+ : page_url_(page_url),
+ icon_url_(icon_url),
+ icon_type_(icon_type),
+ callback_(callback) {
+ }
+
+ HistoryRequestHandler(const GURL& page_url,
+ const GURL& icon_url,
+ int icon_type,
+ const std::vector<unsigned char>& image_data,
+ FaviconService::FaviconDataCallback* callback)
+ : page_url_(page_url),
+ icon_url_(icon_url),
+ icon_type_(icon_type),
+ image_data_(image_data),
+ callback_(callback) {
+ }
+
+ virtual ~HistoryRequestHandler() {
+ delete callback_;
+ }
+ void InvokeCallback();
+
+ const GURL page_url_;
+ const GURL icon_url_;
+ const int icon_type_;
+ const std::vector<unsigned char> image_data_;
+ history::FaviconData favicon_data_;
+ FaviconService::FaviconDataCallback* callback_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HistoryRequestHandler);
+};
+
+} // namespace
+
+// This class is used to catch the FaviconHandler's download and history
+// request, and also provide the methods to access the FaviconHandler internal.
+class TestFaviconHandler : public FaviconHandler {
+ public:
+ TestFaviconHandler(const GURL& page_url,
+ TabContents* tab_contents,
+ Type type)
+ : FaviconHandler(tab_contents, type),
+ download_image_size_(0),
+ download_id_(0),
+ tab_contents_(tab_contents){
+ entry_.set_url(page_url);
+ }
+
+ virtual ~TestFaviconHandler() {
+ }
+
+ HistoryRequestHandler* history_handler() {
+ return history_handler_.get();
+ }
+
+ // This method will take the ownership of the given handler.
+ void set_history_handler(HistoryRequestHandler* handler) {
+ history_handler_.reset(handler);
+ }
+
+ DownloadHandler* download_handler() {
+ return download_handler_.get();
+ }
+
+ // This method will take the ownership of the given download_handler.
+ void set_download_handler(DownloadHandler* download_handler) {
+ download_handler_.reset(download_handler);
+ }
+
+ virtual NavigationEntry* GetEntry() {
+ return &entry_;
+ }
+
+ const std::vector<FaviconURL>& urls() {
+ return urls_;
+ }
+
+ void FetchFavicon(const GURL& url) {
+ FaviconHandler::FetchFavicon(url);
+ }
+
+ // The methods to access favicon internal.
+ FaviconURL* current_candidate() {
+ return FaviconHandler::current_candidate();
+ }
+
+ void OnDidDownloadFavicon(int id,
+ const GURL& image_url,
+ bool errored,
+ const SkBitmap& image) {
+ FaviconHandler::OnDidDownloadFavicon(id, image_url, errored, image);
+ }
+
+ protected:
+ virtual void UpdateFaviconMappingAndFetch(
+ const GURL& page_url,
+ const GURL& icon_url,
+ history::IconType icon_type,
+ CancelableRequestConsumerBase* consumer,
+ FaviconService::FaviconDataCallback* callback) OVERRIDE {
+ history_handler_.reset(new HistoryRequestHandler(page_url, icon_url,
+ icon_type, callback));
+ }
+
+ virtual void GetFavicon(
+ const GURL& icon_url,
+ history::IconType icon_type,
+ CancelableRequestConsumerBase* consumer,
+ FaviconService::FaviconDataCallback* callback) OVERRIDE {
+ history_handler_.reset(new HistoryRequestHandler(GURL(), icon_url,
+ icon_type, callback));
+ }
+
+ virtual void GetFaviconForURL(
+ const GURL& page_url,
+ int icon_types,
+ CancelableRequestConsumerBase* consumer,
+ FaviconService::FaviconDataCallback* callback) OVERRIDE {
+ history_handler_.reset(new HistoryRequestHandler(page_url, GURL(),
+ icon_types, callback));
+ }
+
+ virtual int DownloadFavicon(const GURL& image_url, int image_size) OVERRIDE {
+ download_id_++;
+ download_handler_.reset(new DownloadHandler(download_id_, image_url,
+ image_size, this));
+ return download_id_;
+ }
+
+ virtual void SetHistoryFavicon(const GURL& page_url,
+ const GURL& icon_url,
+ const std::vector<unsigned char>& image_data,
+ history::IconType icon_type) OVERRIDE {
+ history_handler_.reset(new HistoryRequestHandler(page_url, icon_url,
+ icon_type, image_data, NULL));
+ }
+
+ virtual FaviconService* GetFaviconService() OVERRIDE {
+ // Just give none NULL value, so overridden methods can be hit.
+ return (FaviconService*)(1);
+ }
+
+ virtual bool ShouldSaveFavicon(const GURL& url) OVERRIDE {
+ return true;
+ }
+
+ GURL page_url_;
+
+ GURL download_image_url_;
+ int download_image_size_;
+
+ private:
+ NavigationEntry entry_;
+
+ // The unique id of a download request. It will be returned to a
+ // FaviconHandler.
+ int download_id_;
+
+ TabContents* tab_contents_;
+ scoped_ptr<DownloadHandler> download_handler_;
+ scoped_ptr<HistoryRequestHandler> history_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestFaviconHandler);
+};
+
+namespace {
+
+void DownloadHandler::UpdateFaviconURL(FaviconHandler* helper,
+ const std::vector<FaviconURL> urls) {
+ helper->OnUpdateFaviconURL(0, urls);
+}
+
+void DownloadHandler::UpdateFaviconURL(const std::vector<FaviconURL> urls) {
+ UpdateFaviconURL(favicon_helper_, urls);
+}
+
+void DownloadHandler::InvokeCallback() {
+ favicon_helper_->OnDidDownloadFavicon(download_id_, image_url_, failed_,
+ bitmap_);
+}
+
+void HistoryRequestHandler::InvokeCallback() {
+ callback_->Run(0, favicon_data_);
+}
+
+class FaviconHandlerTest : public RenderViewHostTestHarness {
+};
+
+TEST_F(FaviconHandlerTest, GetFaviconFromHistory) {
+ const GURL page_url("http://www.google.com");
+ const GURL icon_url("http://www.google.com/favicon");
+
+ TestFaviconHandler helper(page_url, contents(), FaviconHandler::FAVICON);
+
+ helper.FetchFavicon(page_url);
+ HistoryRequestHandler* history_handler = helper.history_handler();
+ // Ensure the data given to history is correct.
+ ASSERT_TRUE(history_handler);
+ EXPECT_EQ(page_url, history_handler->page_url_);
+ EXPECT_EQ(GURL(), history_handler->icon_url_);
+ EXPECT_EQ(history::FAVICON, history_handler->icon_type_);
+
+ // Set valid icon data.
+ history_handler->favicon_data_.known_icon = true;
+ history_handler->favicon_data_.icon_type = history::FAVICON;
+ history_handler->favicon_data_.expired = false;
+ history_handler->favicon_data_.icon_url = icon_url;
+ scoped_refptr<RefCountedBytes> data = new RefCountedBytes();
+ FillBitmap(kFaviconSize, kFaviconSize, &data->data);
+ history_handler->favicon_data_.image_data = data;
+
+ // Send history response.
+ history_handler->InvokeCallback();
+ // Verify FaviconHandler status
+ EXPECT_TRUE(helper.GetEntry()->favicon().is_valid());
+ EXPECT_EQ(icon_url, helper.GetEntry()->favicon().url());
+
+ // Simulates update favicon url.
+ std::vector<FaviconURL> urls;
+ urls.push_back(FaviconURL(icon_url, FaviconURL::FAVICON));
+ DownloadHandler::UpdateFaviconURL(&helper, urls);
+
+ // Verify FaviconHandler status
+ EXPECT_EQ(1U, helper.urls().size());
+ ASSERT_TRUE(helper.current_candidate());
+ ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
+ ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type);
+
+ // Favicon shouldn't request to download icon.
+ DownloadHandler* download_handler = helper.download_handler();
+ ASSERT_FALSE(download_handler);
+}
+
+TEST_F(FaviconHandlerTest, DownloadFavicon) {
+ const GURL page_url("http://www.google.com");
+ const GURL icon_url("http://www.google.com/favicon");
+
+ TestFaviconHandler helper(page_url, contents(), FaviconHandler::FAVICON);
+
+ helper.FetchFavicon(page_url);
+ HistoryRequestHandler* history_handler = helper.history_handler();
+ // Ensure the data given to history is correct.
+ ASSERT_TRUE(history_handler);
+ EXPECT_EQ(page_url, history_handler->page_url_);
+ EXPECT_EQ(GURL(), history_handler->icon_url_);
+ EXPECT_EQ(history::FAVICON, history_handler->icon_type_);
+
+ // Set icon data expired
+ history_handler->favicon_data_.known_icon = true;
+ history_handler->favicon_data_.icon_type = history::FAVICON;
+ history_handler->favicon_data_.expired = true;
+ history_handler->favicon_data_.icon_url = icon_url;
+ // Send history response.
+ history_handler->InvokeCallback();
+ // Verify FaviconHandler status
+ EXPECT_TRUE(helper.GetEntry()->favicon().is_valid());
+ EXPECT_EQ(icon_url, helper.GetEntry()->favicon().url());
+
+ // Simulates update favicon url.
+ std::vector<FaviconURL> urls;
+ urls.push_back(FaviconURL(icon_url, FaviconURL::FAVICON));
+ DownloadHandler::UpdateFaviconURL(&helper, urls);
+
+ // Verify FaviconHandler status
+ EXPECT_EQ(1U, helper.urls().size());
+ ASSERT_TRUE(helper.current_candidate());
+ ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
+ ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type);
+
+ // Favicon should request to download icon now.
+ DownloadHandler* download_handler = helper.download_handler();
+ ASSERT_TRUE(download_handler);
+ // Verify the download request.
+ EXPECT_EQ(icon_url, download_handler->image_url_);
+ EXPECT_EQ(kFaviconSize, download_handler->image_size_);
+
+ // Reset the history_handler to verify whether favicon is set.
+ helper.set_history_handler(NULL);
+
+ // Smulates download done.
+ download_handler->InvokeCallback();
+
+ // New icon should be saved to history backend and navigation entry.
+ history_handler = helper.history_handler();
+ ASSERT_TRUE(history_handler);
+ EXPECT_EQ(icon_url, history_handler->icon_url_);
+ EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_);
+ EXPECT_LT(0U, history_handler->image_data_.size());
+ EXPECT_EQ(page_url, history_handler->page_url_);
+
+ // Verify NavigationEntry.
+ EXPECT_EQ(icon_url, helper.GetEntry()->favicon().url());
+ EXPECT_TRUE(helper.GetEntry()->favicon().is_valid());
+ EXPECT_FALSE(helper.GetEntry()->favicon().bitmap().empty());
+}
+
+TEST_F(FaviconHandlerTest, UpdateAndDownloadFavicon) {
+ const GURL page_url("http://www.google.com");
+ const GURL icon_url("http://www.google.com/favicon");
+ const GURL new_icon_url("http://www.google.com/new_favicon");
+
+ TestFaviconHandler helper(page_url, contents(), FaviconHandler::FAVICON);
+
+ helper.FetchFavicon(page_url);
+ HistoryRequestHandler* history_handler = helper.history_handler();
+ // Ensure the data given to history is correct.
+ ASSERT_TRUE(history_handler);
+ EXPECT_EQ(page_url, history_handler->page_url_);
+ EXPECT_EQ(GURL(), history_handler->icon_url_);
+ EXPECT_EQ(history::FAVICON, history_handler->icon_type_);
+
+ // Set valid icon data.
+ history_handler->favicon_data_.known_icon = true;
+ history_handler->favicon_data_.icon_type = history::FAVICON;
+ history_handler->favicon_data_.expired = false;
+ history_handler->favicon_data_.icon_url = icon_url;
+ scoped_refptr<RefCountedBytes> data = new RefCountedBytes();
+ FillBitmap(kFaviconSize, kFaviconSize, &data->data);
+ history_handler->favicon_data_.image_data = data;
+
+ // Send history response.
+ history_handler->InvokeCallback();
+ // Verify FaviconHandler status.
+ EXPECT_TRUE(helper.GetEntry()->favicon().is_valid());
+ EXPECT_EQ(icon_url, helper.GetEntry()->favicon().url());
+
+ // Reset the history_handler to verify whether new icon is requested from
+ // history.
+ helper.set_history_handler(NULL);
+
+ // Simulates update with the different favicon url.
+ std::vector<FaviconURL> urls;
+ urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON));
+ DownloadHandler::UpdateFaviconURL(&helper, urls);
+
+ // Verify FaviconHandler status.
+ EXPECT_EQ(1U, helper.urls().size());
+ ASSERT_TRUE(helper.current_candidate());
+ ASSERT_EQ(new_icon_url, helper.current_candidate()->icon_url);
+ ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type);
+ // The favicon status's url should be updated.
+ ASSERT_EQ(new_icon_url, helper.GetEntry()->favicon().url());
+
+ // Favicon should be requested from history.
+ history_handler = helper.history_handler();
+ ASSERT_TRUE(history_handler);
+ EXPECT_EQ(new_icon_url, history_handler->icon_url_);
+ EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_);
+ EXPECT_EQ(page_url, history_handler->page_url_);
+
+ // Simulate not find icon.
+ history_handler->favicon_data_.known_icon = false;
+ history_handler->InvokeCallback();
+
+ // Favicon should request to download icon now.
+ DownloadHandler* download_handler = helper.download_handler();
+ ASSERT_TRUE(download_handler);
+ // Verify the download request.
+ EXPECT_EQ(new_icon_url, download_handler->image_url_);
+ EXPECT_EQ(kFaviconSize, download_handler->image_size_);
+
+ // Reset the history_handler to verify whether favicon is set.
+ helper.set_history_handler(NULL);
+
+ // Smulates download done.
+ download_handler->InvokeCallback();
+
+ // New icon should be saved to history backend and navigation entry.
+ history_handler = helper.history_handler();
+ ASSERT_TRUE(history_handler);
+ EXPECT_EQ(new_icon_url, history_handler->icon_url_);
+ EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_);
+ EXPECT_LT(0U, history_handler->image_data_.size());
+ EXPECT_EQ(page_url, history_handler->page_url_);
+
+ // Verify NavigationEntry.
+ EXPECT_EQ(new_icon_url, helper.GetEntry()->favicon().url());
+ EXPECT_TRUE(helper.GetEntry()->favicon().is_valid());
+ EXPECT_FALSE(helper.GetEntry()->favicon().bitmap().empty());
+}
+
+TEST_F(FaviconHandlerTest, UpdateFavicon) {
+ const GURL page_url("http://www.google.com");
+ const GURL icon_url("http://www.google.com/favicon");
+ const GURL new_icon_url("http://www.google.com/new_favicon");
+
+ TestFaviconHandler helper(page_url, contents(), FaviconHandler::FAVICON);
+
+ helper.FetchFavicon(page_url);
+ HistoryRequestHandler* history_handler = helper.history_handler();
+ // Ensure the data given to history is correct.
+ ASSERT_TRUE(history_handler);
+ EXPECT_EQ(page_url, history_handler->page_url_);
+ EXPECT_EQ(GURL(), history_handler->icon_url_);
+ EXPECT_EQ(history::FAVICON, history_handler->icon_type_);
+
+ // Set valid icon data.
+ history_handler->favicon_data_.known_icon = true;
+ history_handler->favicon_data_.icon_type = history::FAVICON;
+ history_handler->favicon_data_.expired = false;
+ history_handler->favicon_data_.icon_url = icon_url;
+ scoped_refptr<RefCountedBytes> data = new RefCountedBytes();
+ FillBitmap(kFaviconSize, kFaviconSize, &data->data);
+ history_handler->favicon_data_.image_data = data;
+
+ // Send history response.
+ history_handler->InvokeCallback();
+ // Verify FaviconHandler status.
+ EXPECT_TRUE(helper.GetEntry()->favicon().is_valid());
+ EXPECT_EQ(icon_url, helper.GetEntry()->favicon().url());
+
+ // Reset the history_handler to verify whether new icon is requested from
+ // history.
+ helper.set_history_handler(NULL);
+
+ // Simulates update with the different favicon url.
+ std::vector<FaviconURL> urls;
+ urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON));
+ DownloadHandler::UpdateFaviconURL(&helper, urls);
+
+ // Verify FaviconHandler status.
+ EXPECT_EQ(1U, helper.urls().size());
+ ASSERT_TRUE(helper.current_candidate());
+ ASSERT_EQ(new_icon_url, helper.current_candidate()->icon_url);
+ ASSERT_EQ(FaviconURL::FAVICON, helper.current_candidate()->icon_type);
+ // The favicon status's url should be updated.
+ ASSERT_EQ(new_icon_url, helper.GetEntry()->favicon().url());
+
+ // Favicon should be requested from history.
+ history_handler = helper.history_handler();
+ ASSERT_TRUE(history_handler);
+ EXPECT_EQ(new_icon_url, history_handler->icon_url_);
+ EXPECT_EQ(FaviconURL::FAVICON, history_handler->icon_type_);
+ EXPECT_EQ(page_url, history_handler->page_url_);
+
+ // Simulate find icon.
+ history_handler->favicon_data_.known_icon = true;
+ history_handler->favicon_data_.icon_type = history::FAVICON;
+ history_handler->favicon_data_.expired = false;
+ history_handler->favicon_data_.icon_url = new_icon_url;
+ history_handler->favicon_data_.image_data = data;
+ history_handler->InvokeCallback();
+
+ // Shouldn't request download favicon
+ EXPECT_FALSE(helper.download_handler());
+
+ // Verify the favicon status.
+ EXPECT_EQ(new_icon_url, helper.GetEntry()->favicon().url());
+ EXPECT_TRUE(helper.GetEntry()->favicon().is_valid());
+ EXPECT_FALSE(helper.GetEntry()->favicon().bitmap().empty());
+}
+
+TEST_F(FaviconHandlerTest, Download2ndFaviconURLCandidate) {
+ const GURL page_url("http://www.google.com");
+ const GURL icon_url("http://www.google.com/favicon");
+ const GURL new_icon_url("http://www.google.com/new_favicon");
+
+ TestFaviconHandler helper(page_url, contents(), FaviconHandler::TOUCH);
+
+ helper.FetchFavicon(page_url);
+ HistoryRequestHandler* history_handler = helper.history_handler();
+ // Ensure the data given to history is correct.
+ ASSERT_TRUE(history_handler);
+ EXPECT_EQ(page_url, history_handler->page_url_);
+ EXPECT_EQ(GURL(), history_handler->icon_url_);
+ EXPECT_EQ(history::TOUCH_PRECOMPOSED_ICON | history::TOUCH_ICON,
+ history_handler->icon_type_);
+
+ // Icon not found.
+ history_handler->favicon_data_.known_icon = false;
+ // Send history response.
+ history_handler->InvokeCallback();
+ // Verify FaviconHandler status.
+ EXPECT_FALSE(helper.GetEntry()->favicon().is_valid());
+ EXPECT_EQ(GURL(), helper.GetEntry()->favicon().url());
+
+ // Reset the history_handler to verify whether new icon is requested from
+ // history.
+ helper.set_history_handler(NULL);
+
+ // Simulates update with the different favicon url.
+ std::vector<FaviconURL> urls;
+ urls.push_back(FaviconURL(icon_url, FaviconURL::TOUCH_PRECOMPOSED_ICON));
+ urls.push_back(FaviconURL(new_icon_url, FaviconURL::TOUCH_ICON));
+ urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON));
+
+ DownloadHandler::UpdateFaviconURL(&helper, urls);
+
+ // Verify FaviconHandler status.
+ EXPECT_EQ(2U, helper.urls().size());
+ ASSERT_TRUE(helper.current_candidate());
+ ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
+ ASSERT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON,
+ helper.current_candidate()->icon_type);
+
+ // Favicon should be requested from history.
+ history_handler = helper.history_handler();
+ ASSERT_TRUE(history_handler);
+ EXPECT_EQ(icon_url, history_handler->icon_url_);
+ EXPECT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON, history_handler->icon_type_);
+ EXPECT_EQ(page_url, history_handler->page_url_);
+
+ // Simulate not find icon.
+ history_handler->favicon_data_.known_icon = false;
+ history_handler->InvokeCallback();
+
+ // Should request download favicon.
+ DownloadHandler* download_handler = helper.download_handler();
+ EXPECT_TRUE(download_handler);
+ // Verify the download request.
+ EXPECT_EQ(icon_url, download_handler->image_url_);
+ EXPECT_EQ(0, download_handler->image_size_);
+
+ // Reset the history_handler to verify whether favicon is request from
+ // history.
+ helper.set_history_handler(NULL);
+ // Smulates download failed.
+ download_handler->failed_ = true;
+ download_handler->InvokeCallback();
+
+ // Left 1 url.
+ EXPECT_EQ(1U, helper.urls().size());
+ ASSERT_TRUE(helper.current_candidate());
+ EXPECT_EQ(new_icon_url, helper.current_candidate()->icon_url);
+ EXPECT_EQ(FaviconURL::TOUCH_ICON, helper.current_candidate()->icon_type);
+
+ // Favicon should be requested from history.
+ history_handler = helper.history_handler();
+ ASSERT_TRUE(history_handler);
+ EXPECT_EQ(new_icon_url, history_handler->icon_url_);
+ EXPECT_EQ(FaviconURL::TOUCH_ICON, history_handler->icon_type_);
+ EXPECT_EQ(page_url, history_handler->page_url_);
+
+ // Reset download handler
+ helper.set_download_handler(NULL);
+
+ // Smulates getting a expired icon from history.
+ history_handler->favicon_data_.known_icon = true;
+ history_handler->favicon_data_.icon_type = history::TOUCH_ICON;
+ history_handler->favicon_data_.expired = true;
+ history_handler->favicon_data_.icon_url = new_icon_url;
+ scoped_refptr<RefCountedBytes> data = new RefCountedBytes();
+ FillBitmap(kFaviconSize, kFaviconSize, &data->data);
+ history_handler->favicon_data_.image_data = data;
+ history_handler->InvokeCallback();
+
+ // Verify the download request.
+ download_handler = helper.download_handler();
+ EXPECT_TRUE(download_handler);
+ EXPECT_EQ(new_icon_url, download_handler->image_url_);
+ EXPECT_EQ(0, download_handler->image_size_);
+
+ helper.set_history_handler(NULL);
+
+ // Simulates icon being downloaded.
+ download_handler->InvokeCallback();
+
+ // New icon should be saved to history backend.
+ history_handler = helper.history_handler();
+ ASSERT_TRUE(history_handler);
+ EXPECT_EQ(new_icon_url, history_handler->icon_url_);
+ EXPECT_EQ(FaviconURL::TOUCH_ICON, history_handler->icon_type_);
+ EXPECT_LT(0U, history_handler->image_data_.size());
+ EXPECT_EQ(page_url, history_handler->page_url_);
+}
+
+TEST_F(FaviconHandlerTest, UpdateDuringDownloading) {
+ const GURL page_url("http://www.google.com");
+ const GURL icon_url("http://www.google.com/favicon");
+ const GURL new_icon_url("http://www.google.com/new_favicon");
+
+ TestFaviconHandler helper(page_url, contents(), FaviconHandler::TOUCH);
+
+ helper.FetchFavicon(page_url);
+ HistoryRequestHandler* history_handler = helper.history_handler();
+ // Ensure the data given to history is correct.
+ ASSERT_TRUE(history_handler);
+ EXPECT_EQ(page_url, history_handler->page_url_);
+ EXPECT_EQ(GURL(), history_handler->icon_url_);
+ EXPECT_EQ(history::TOUCH_PRECOMPOSED_ICON | history::TOUCH_ICON,
+ history_handler->icon_type_);
+
+ // Icon not found.
+ history_handler->favicon_data_.known_icon = false;
+ // Send history response.
+ history_handler->InvokeCallback();
+ // Verify FaviconHandler status.
+ EXPECT_FALSE(helper.GetEntry()->favicon().is_valid());
+ EXPECT_EQ(GURL(), helper.GetEntry()->favicon().url());
+
+ // Reset the history_handler to verify whether new icon is requested from
+ // history.
+ helper.set_history_handler(NULL);
+
+ // Simulates update with the different favicon url.
+ std::vector<FaviconURL> urls;
+ urls.push_back(FaviconURL(icon_url, FaviconURL::TOUCH_PRECOMPOSED_ICON));
+ urls.push_back(FaviconURL(new_icon_url, FaviconURL::TOUCH_ICON));
+ urls.push_back(FaviconURL(new_icon_url, FaviconURL::FAVICON));
+
+ DownloadHandler::UpdateFaviconURL(&helper, urls);
+
+ // Verify FaviconHandler status.
+ EXPECT_EQ(2U, helper.urls().size());
+ ASSERT_TRUE(helper.current_candidate());
+ ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
+ ASSERT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON,
+ helper.current_candidate()->icon_type);
+
+ // Favicon should be requested from history.
+ history_handler = helper.history_handler();
+ ASSERT_TRUE(history_handler);
+ EXPECT_EQ(icon_url, history_handler->icon_url_);
+ EXPECT_EQ(FaviconURL::TOUCH_PRECOMPOSED_ICON, history_handler->icon_type_);
+ EXPECT_EQ(page_url, history_handler->page_url_);
+
+ // Simulate not find icon.
+ history_handler->favicon_data_.known_icon = false;
+ history_handler->InvokeCallback();
+
+ // Should request download favicon.
+ DownloadHandler* download_handler = helper.download_handler();
+ EXPECT_TRUE(download_handler);
+ // Verify the download request.
+ EXPECT_EQ(icon_url, download_handler->image_url_);
+ EXPECT_EQ(0, download_handler->image_size_);
+
+ // Reset the history_handler to verify whether favicon is request from
+ // history.
+ helper.set_history_handler(NULL);
+ const GURL latest_icon_url("http://www.google.com/latest_favicon");
+ std::vector<FaviconURL> latest_urls;
+ latest_urls.push_back(FaviconURL(latest_icon_url, FaviconURL::TOUCH_ICON));
+ DownloadHandler::UpdateFaviconURL(&helper, latest_urls);
+ EXPECT_EQ(1U, helper.urls().size());
+ EXPECT_EQ(latest_icon_url, helper.current_candidate()->icon_url);
+ EXPECT_EQ(FaviconURL::TOUCH_ICON, helper.current_candidate()->icon_type);
+
+ // Whether new icon is requested from history
+ history_handler = helper.history_handler();
+ ASSERT_TRUE(history_handler);
+ EXPECT_EQ(latest_icon_url, history_handler->icon_url_);
+ EXPECT_EQ(FaviconURL::TOUCH_ICON, history_handler->icon_type_);
+ EXPECT_EQ(page_url, history_handler->page_url_);
+
+ // Reset the history_handler to verify whether favicon is request from
+ // history.
+ // Save the callback for late use.
+ FaviconService::FaviconDataCallback* callback = history_handler->callback_;
+ // Prevent the callback from being released.
+ history_handler->callback_ = NULL;
+ helper.set_history_handler(NULL);
+
+ // Smulates download succeed.
+ download_handler->InvokeCallback();
+ // The downloaded icon should be thrown away as there is faviocn update.
+ EXPECT_FALSE(helper.history_handler());
+
+ helper.set_download_handler(NULL);
+
+ // Smulates getting the icon from history.
+ scoped_ptr<HistoryRequestHandler> handler;
+ handler.reset(new HistoryRequestHandler(page_url, latest_icon_url,
+ history::TOUCH_ICON, callback));
+ handler->favicon_data_.known_icon = true;
+ handler->favicon_data_.expired = false;
+ handler->favicon_data_.icon_type = history::TOUCH_ICON;
+ handler->favicon_data_.icon_url = latest_icon_url;
+ scoped_refptr<RefCountedBytes> data = new RefCountedBytes();
+ FillBitmap(kFaviconSize, kFaviconSize, &data->data);
+ handler->favicon_data_.image_data = data;
+
+ handler->InvokeCallback();
+
+ // No download request.
+ EXPECT_FALSE(helper.download_handler());
+}
+
+} // namespace.
diff --git a/chrome/browser/favicon/favicon_service.cc b/chrome/browser/favicon/favicon_service.cc
new file mode 100644
index 0000000..a276c7c
--- /dev/null
+++ b/chrome/browser/favicon/favicon_service.cc
@@ -0,0 +1,97 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/favicon/favicon_service.h"
+
+#include "chrome/browser/history/history.h"
+#include "chrome/browser/history/history_backend.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/webui/chrome_web_ui_factory.h"
+#include "chrome/common/url_constants.h"
+
+FaviconService::FaviconService(Profile* profile) : profile_(profile) {
+}
+
+FaviconService::Handle FaviconService::GetFavicon(
+ const GURL& icon_url,
+ history::IconType icon_type,
+ CancelableRequestConsumerBase* consumer,
+ FaviconDataCallback* callback) {
+ GetFaviconRequest* request = new GetFaviconRequest(callback);
+ AddRequest(request, consumer);
+ HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ if (hs)
+ hs->GetFavicon(request, icon_url, icon_type);
+ else
+ ForwardEmptyResultAsync(request);
+ return request->handle();
+}
+
+FaviconService::Handle FaviconService::UpdateFaviconMappingAndFetch(
+ const GURL& page_url,
+ const GURL& icon_url,
+ history::IconType icon_type,
+ CancelableRequestConsumerBase* consumer,
+ FaviconService::FaviconDataCallback* callback) {
+ GetFaviconRequest* request = new GetFaviconRequest(callback);
+ AddRequest(request, consumer);
+ HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ if (hs)
+ hs->UpdateFaviconMappingAndFetch(request, page_url, icon_url, icon_type);
+ else
+ ForwardEmptyResultAsync(request);
+ return request->handle();
+}
+
+FaviconService::Handle FaviconService::GetFaviconForURL(
+ const GURL& page_url,
+ int icon_types,
+ CancelableRequestConsumerBase* consumer,
+ FaviconDataCallback* callback) {
+ GetFaviconRequest* request = new GetFaviconRequest(callback);
+ AddRequest(request, consumer);
+ FaviconService::Handle handle = request->handle();
+ if (page_url.SchemeIs(chrome::kChromeUIScheme) ||
+ page_url.SchemeIs(chrome::kExtensionScheme)) {
+ ChromeWebUIFactory::GetInstance()->GetFaviconForURL(
+ profile_, request, page_url);
+ } else {
+ HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ if (hs)
+ hs->GetFaviconForURL(request, page_url, icon_types);
+ else
+ ForwardEmptyResultAsync(request);
+ }
+ return handle;
+}
+
+void FaviconService::SetFaviconOutOfDateForPage(const GURL& page_url) {
+ HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ if (hs)
+ hs->SetFaviconOutOfDateForPage(page_url);
+}
+
+void FaviconService::SetImportedFavicons(
+ const std::vector<history::ImportedFaviconUsage>& favicon_usage) {
+ HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ if (hs)
+ hs->SetImportedFavicons(favicon_usage);
+}
+
+void FaviconService::SetFavicon(const GURL& page_url,
+ const GURL& icon_url,
+ const std::vector<unsigned char>& image_data,
+ history::IconType icon_type) {
+ HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
+ if (hs)
+ hs->SetFavicon(page_url, icon_url, image_data, icon_type);
+}
+
+FaviconService::~FaviconService() {
+}
+
+void FaviconService::ForwardEmptyResultAsync(GetFaviconRequest* request) {
+ request->ForwardResultAsync(FaviconDataCallback::TupleType(
+ request->handle(), history::FaviconData()));
+}
diff --git a/chrome/browser/favicon/favicon_service.h b/chrome/browser/favicon/favicon_service.h
new file mode 100644
index 0000000..48d81e8
--- /dev/null
+++ b/chrome/browser/favicon/favicon_service.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_FAVICON_FAVICON_SERVICE_H_
+#define CHROME_BROWSER_FAVICON_FAVICON_SERVICE_H_
+#pragma once
+
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/task.h"
+#include "chrome/browser/history/history_types.h"
+#include "chrome/common/ref_counted_util.h"
+#include "content/browser/cancelable_request.h"
+
+class GURL;
+class Profile;
+
+// The favicon service provides methods to access favicons. It calls the history
+// backend behind the scenes.
+//
+// This service is thread safe. Each request callback is invoked in the
+// thread that made the request.
+class FaviconService : public CancelableRequestProvider,
+ public base::RefCountedThreadSafe<FaviconService> {
+ public:
+ explicit FaviconService(Profile* profile);
+
+ // Callback for GetFavicon. If we have previously inquired about the favicon
+ // for this URL, |know_favicon| will be true, and the rest of the fields will
+ // be valid (otherwise they will be ignored).
+ //
+ // On |know_favicon| == true, |data| will either contain the PNG encoded
+ // favicon data, or it will be NULL to indicate that the site does not have
+ // a favicon (in other words, we know the site doesn't have a favicon, as
+ // opposed to not knowing anything). |expired| will be set to true if we
+ // refreshed the favicon "too long" ago and should be updated if the page
+ // is visited again.
+ typedef Callback2<Handle, // handle
+ history::FaviconData>::Type // the type of favicon
+ FaviconDataCallback;
+
+ typedef CancelableRequest<FaviconDataCallback> GetFaviconRequest;
+
+ // Requests the |icon_type| of favicon. |consumer| is notified when the bits
+ // have been fetched.
+ Handle GetFavicon(const GURL& icon_url,
+ history::IconType icon_type,
+ CancelableRequestConsumerBase* consumer,
+ FaviconDataCallback* callback);
+
+ // Fetches the |icon_type| of favicon at |icon_url|, sending the results to
+ // the given |callback|. If the favicon has previously been set via
+ // SetFavicon(), then the favicon URL for |page_url| and all redirects is set
+ // to |icon_url|. If the favicon has not been set, the database is not
+ // updated.
+ Handle UpdateFaviconMappingAndFetch(const GURL& page_url,
+ const GURL& icon_url,
+ history::IconType icon_type,
+ CancelableRequestConsumerBase* consumer,
+ FaviconDataCallback* callback);
+
+ // Requests any |icon_types| of favicon for a web page URL. |consumer| is
+ // notified when the bits have been fetched. |icon_types| can be any
+ // combination of IconType value, but only one icon will be returned in the
+ // priority of TOUCH_PRECOMPOSED_ICON, TOUCH_ICON and FAVICON.
+ //
+ // Note: this version is intended to be used to retrieve the favicon of a
+ // page that has been browsed in the past. |expired| in the callback is
+ // always false.
+ Handle GetFaviconForURL(const GURL& page_url,
+ int icon_types,
+ CancelableRequestConsumerBase* consumer,
+ FaviconDataCallback* callback);
+
+ // Marks all types of favicon for the page as being out of date.
+ void SetFaviconOutOfDateForPage(const GURL& page_url);
+
+ // Allows the importer to set many favicons for many pages at once. The pages
+ // must exist, any favicon sets for unknown pages will be discarded. Existing
+ // favicons will not be overwritten.
+ void SetImportedFavicons(
+ const std::vector<history::ImportedFaviconUsage>& favicon_usage);
+
+ // Sets the favicon for a page.
+ void SetFavicon(const GURL& page_url,
+ const GURL& icon_url,
+ const std::vector<unsigned char>& image_data,
+ history::IconType icon_type);
+
+ private:
+ friend class base::RefCountedThreadSafe<FaviconService>;
+
+ ~FaviconService();
+
+ Profile* profile_;
+
+ // Helper to forward an empty result if we cannot get the history service.
+ void ForwardEmptyResultAsync(GetFaviconRequest* request);
+
+ DISALLOW_COPY_AND_ASSIGN(FaviconService);
+};
+
+#endif // CHROME_BROWSER_FAVICON_FAVICON_SERVICE_H_
diff --git a/chrome/browser/favicon/favicon_tab_helper.cc b/chrome/browser/favicon/favicon_tab_helper.cc
new file mode 100644
index 0000000..f6908fb
--- /dev/null
+++ b/chrome/browser/favicon/favicon_tab_helper.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/favicon/favicon_tab_helper.h"
+
+#include "chrome/browser/defaults.h"
+#include "chrome/browser/favicon/favicon_handler.h"
+#include "chrome/common/icon_messages.h"
+
+FaviconTabHelper::FaviconTabHelper(TabContents* tab_contents)
+ : TabContentsObserver(tab_contents) {
+ favicon_handler_.reset(new FaviconHandler(tab_contents,
+ FaviconHandler::FAVICON));
+ if (browser_defaults::kEnableTouchIcon)
+ touch_icon_handler_.reset(new FaviconHandler(tab_contents,
+ FaviconHandler::TOUCH));
+}
+
+FaviconTabHelper::~FaviconTabHelper() {
+}
+
+void FaviconTabHelper::FetchFavicon(const GURL& url) {
+ favicon_handler_->FetchFavicon(url);
+ if (touch_icon_handler_.get())
+ touch_icon_handler_->FetchFavicon(url);
+}
+
+int FaviconTabHelper::DownloadImage(const GURL& image_url,
+ int image_size,
+ history::IconType icon_type,
+ ImageDownloadCallback* callback) {
+ if (icon_type == history::FAVICON)
+ return favicon_handler_->DownloadImage(image_url, image_size, icon_type,
+ callback);
+ else if (touch_icon_handler_.get())
+ return touch_icon_handler_->DownloadImage(image_url, image_size, icon_type,
+ callback);
+ return 0;
+}
+
+bool FaviconTabHelper::OnMessageReceived(const IPC::Message& message) {
+ bool message_handled = true;
+ IPC_BEGIN_MESSAGE_MAP(FaviconTabHelper, message)
+ IPC_MESSAGE_HANDLER(IconHostMsg_DidDownloadFavicon, OnDidDownloadFavicon)
+ IPC_MESSAGE_HANDLER(IconHostMsg_UpdateFaviconURL, OnUpdateFaviconURL)
+ IPC_MESSAGE_UNHANDLED(message_handled = false)
+ IPC_END_MESSAGE_MAP()
+ return message_handled;
+}
+
+void FaviconTabHelper::OnDidDownloadFavicon(int id,
+ const GURL& image_url,
+ bool errored,
+ const SkBitmap& image) {
+ favicon_handler_->OnDidDownloadFavicon(id, image_url, errored, image);
+ if (touch_icon_handler_.get())
+ touch_icon_handler_->OnDidDownloadFavicon(id, image_url, errored, image);
+}
+
+void FaviconTabHelper::OnUpdateFaviconURL(
+ int32 page_id,
+ const std::vector<FaviconURL>& candidates) {
+ favicon_handler_->OnUpdateFaviconURL(page_id, candidates);
+ if (touch_icon_handler_.get())
+ touch_icon_handler_->OnUpdateFaviconURL(page_id, candidates);
+}
diff --git a/chrome/browser/favicon/favicon_tab_helper.h b/chrome/browser/favicon/favicon_tab_helper.h
new file mode 100644
index 0000000..64064f4
--- /dev/null
+++ b/chrome/browser/favicon/favicon_tab_helper.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_FAVICON_FAVICON_TAB_HELPER_H_
+#define CHROME_BROWSER_FAVICON_FAVICON_TAB_HELPER_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "chrome/browser/favicon/favicon_service.h"
+#include "chrome/common/favicon_url.h"
+#include "content/browser/tab_contents/tab_contents_observer.h"
+#include "googleurl/src/gurl.h"
+
+class FaviconHandler;
+class NavigationEntry;
+class Profile;
+class RefCountedMemory;
+class SkBitmap;
+class TabContents;
+
+// FaviconTabHelper works with FaviconHandlers to fetch the favicons.
+//
+// FetchFavicon fetches the given page's icons. It requests the icons from the
+// history backend. If the icon is not available or expired, the icon will be
+// downloaded and saved in the history backend.
+//
+// DownloadImage downloads the specified icon and returns it through the given
+// callback.
+//
+class FaviconTabHelper : public TabContentsObserver {
+ public:
+ explicit FaviconTabHelper(TabContents* tab_contents);
+ virtual ~FaviconTabHelper();
+
+ // Initiates loading the favicon for the specified url.
+ void FetchFavicon(const GURL& url);
+
+ // Initiates loading an image from given |image_url|. Returns a download id
+ // for caller to track the request. When download completes, |callback| is
+ // called with the three params: the download_id, a boolean flag to indicate
+ // whether the download succeeds and a SkBitmap as the downloaded image.
+ // Note that |image_size| is a hint for images with multiple sizes. The
+ // downloaded image is not resized to the given image_size. If 0 is passed,
+ // the first frame of the image is returned.
+ typedef Callback3<int, bool, const SkBitmap&>::Type ImageDownloadCallback;
+ int DownloadImage(const GURL& image_url,
+ int image_size,
+ history::IconType icon_type,
+ ImageDownloadCallback* callback);
+
+ // Message Handler. Must be public, because also called from
+ // PrerenderContents.
+ void OnUpdateFaviconURL(int32 page_id,
+ const std::vector<FaviconURL>& candidates);
+
+ private:
+ // TabContentsObserver overrides.
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ void OnDidDownloadFavicon(int id,
+ const GURL& image_url,
+ bool errored,
+ const SkBitmap& image);
+
+ scoped_ptr<FaviconHandler> favicon_handler_;
+
+ // Handles downloading touchicons. It is NULL if
+ // browser_defaults::kEnableTouchIcon is false.
+ scoped_ptr<FaviconHandler> touch_icon_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(FaviconTabHelper);
+};
+
+#endif // CHROME_BROWSER_FAVICON_FAVICON_TAB_HELPER_H_