summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormichaelbai@google.com <michaelbai@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-11 21:40:46 +0000
committermichaelbai@google.com <michaelbai@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-11 21:40:46 +0000
commit351ef3bc6f4ef78a1a8a5e9ccf2bdf0e3ec38e65 (patch)
tree15756795df3c94317f518cda23697ccacadea46a
parent639e57d0e1d79f996733d81285c6604314ca9cde (diff)
downloadchromium_src-351ef3bc6f4ef78a1a8a5e9ccf2bdf0e3ec38e65.zip
chromium_src-351ef3bc6f4ef78a1a8a5e9ccf2bdf0e3ec38e65.tar.gz
chromium_src-351ef3bc6f4ef78a1a8a5e9ccf2bdf0e3ec38e65.tar.bz2
a Downloaded or retrieved favicon and touch in FaviconHelper.
b.ViewHostMsg_UpdateFaviconURL can update multiple icon urls BUG=71571 TEST=Tested with existing unit test and add 2 new unit tests Review URL: http://codereview.chromium.org/6672065 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81158 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/defaults.cc2
-rw-r--r--chrome/browser/defaults.h5
-rw-r--r--chrome/browser/favicon_helper.cc310
-rw-r--r--chrome/browser/favicon_helper.h139
-rw-r--r--chrome/browser/favicon_helper_unittest.cc762
-rw-r--r--chrome/browser/prerender/prerender_contents.cc15
-rw-r--r--chrome/browser/prerender/prerender_contents.h3
-rw-r--r--chrome/browser/prerender/prerender_manager.cc8
-rw-r--r--chrome/browser/ui/views/create_application_shortcut_view.cc1
-rw-r--r--chrome/browser/ui/web_applications/web_app_ui.cc1
-rw-r--r--chrome/browser/ui/webui/most_visited_handler.cc4
-rw-r--r--chrome/chrome_common.gypi2
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/icon_messages.cc60
-rw-r--r--chrome/common/icon_messages.h57
-rw-r--r--chrome/common/render_messages.h5
-rw-r--r--content/browser/tab_contents/tab_contents.cc16
-rw-r--r--content/browser/tab_contents/tab_contents.h6
-rw-r--r--content/renderer/render_view.cc16
19 files changed, 1270 insertions, 143 deletions
diff --git a/chrome/browser/defaults.cc b/chrome/browser/defaults.cc
index 9cb34d7..f5a0c0f 100644
--- a/chrome/browser/defaults.cc
+++ b/chrome/browser/defaults.cc
@@ -68,6 +68,8 @@ const bool kAlwaysOpenIncognitoWindow = false;
const bool kShowCancelButtonInTaskManager = false;
#endif
+const bool kEnableTouchIcon = false;
+
#if defined(OS_MACOSX)
const bool kBrowserAliveWithNoWindows = true;
#else
diff --git a/chrome/browser/defaults.h b/chrome/browser/defaults.h
index dd06dbe..e733675 100644
--- a/chrome/browser/defaults.h
+++ b/chrome/browser/defaults.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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.
@@ -68,6 +68,9 @@ extern const bool kAlwaysOpenIncognitoWindow;
// Should the close button be shown in the Task Manager dialog?
extern const bool kShowCancelButtonInTaskManager;
+// Are touch icons enabled? False by default.
+extern const bool kEnableTouchIcon;
+
//=============================================================================
// Runtime "const" - set only once after parsing command line option and should
// never be modified after that.
diff --git a/chrome/browser/favicon_helper.cc b/chrome/browser/favicon_helper.cc
index 1e5206b..6479c69 100644
--- a/chrome/browser/favicon_helper.cc
+++ b/chrome/browser/favicon_helper.cc
@@ -20,13 +20,29 @@
#include "content/browser/tab_contents/tab_contents.h"
#include "skia/ext/image_operations.h"
#include "ui/gfx/codec/png_codec.h"
-#include "ui/gfx/favicon_size.h"
-FaviconHelper::FaviconHelper(TabContents* tab_contents)
+FaviconHelper::DownloadRequest::DownloadRequest()
+ : callback(NULL),
+ icon_type(history::INVALID_ICON) {
+}
+
+FaviconHelper::DownloadRequest::DownloadRequest(const GURL& url,
+ const GURL& image_url,
+ ImageDownloadCallback* callback,
+ history::IconType icon_type)
+ : url(url),
+ image_url(image_url),
+ callback(callback),
+ icon_type(icon_type) {
+}
+
+FaviconHelper::FaviconHelper(TabContents* tab_contents, Type icon_type)
: TabContentsObserver(tab_contents),
- got_favicon_url_(false),
got_favicon_from_history_(false),
- favicon_expired_(false) {
+ favicon_expired_(false),
+ icon_types_(icon_type == FAVICON ? history::FAVICON :
+ history::TOUCH_ICON | history::TOUCH_PRECOMPOSED_ICON),
+ current_url_index_(0) {
}
FaviconHelper::~FaviconHelper() {
@@ -46,49 +62,48 @@ void FaviconHelper::FetchFavicon(const GURL& url) {
url_ = url;
- favicon_expired_ = got_favicon_from_history_ = got_favicon_url_ = false;
+ 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()) {
- GetFaviconService()->GetFaviconForURL(url_, history::FAVICON,
- &cancelable_consumer_,
+ GetFaviconForURL(url_, icon_types_, &cancelable_consumer_,
NewCallback(this, &FaviconHelper::OnFaviconDataForInitialURL));
}
}
int FaviconHelper::DownloadImage(const GURL& image_url,
int image_size,
+ history::IconType icon_type,
ImageDownloadCallback* callback) {
DCHECK(callback); // Must provide a callback.
- return ScheduleDownload(GURL(), image_url, image_size, callback);
-}
-
-Profile* FaviconHelper::profile() {
- return tab_contents()->profile();
+ return ScheduleDownload(GURL(), image_url, image_size, icon_type, callback);
}
FaviconService* FaviconHelper::GetFaviconService() {
- return profile()->GetFaviconService(Profile::EXPLICIT_ACCESS);
+ return tab_contents()->profile()->GetFaviconService(Profile::EXPLICIT_ACCESS);
}
void FaviconHelper::SetFavicon(
const GURL& url,
const GURL& image_url,
- const SkBitmap& image) {
- const SkBitmap& sized_image =
- (image.width() == kFaviconSize && image.height() == kFaviconSize)
- ? image : ConvertToFaviconSize(image);
+ 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);
- GetFaviconService()->SetFavicon(url, image_url, image_data,
- history::FAVICON);
+ SetHistoryFavicon(url, image_url, image_data, icon_type);
}
- if (url == url_) {
+ if (url == url_ && icon_type == history::FAVICON) {
NavigationEntry* entry = GetEntry();
if (entry)
UpdateFavicon(entry, sized_image);
@@ -114,41 +129,138 @@ void FaviconHelper::UpdateFavicon(NavigationEntry* entry,
tab_contents()->NotifyNavigationStateChanged(TabContents::INVALIDATE_TAB);
}
-void FaviconHelper::OnUpdateFaviconURL(int32 page_id, const GURL& icon_url) {
- // TODO(davemoore) Should clear on empty url. Currently we ignore it.
- // This appears to be what FF does as well.
- if (icon_url.is_empty())
- return;
-
+void FaviconHelper::OnUpdateFaviconURL(
+ int32 page_id,
+ const std::vector<FaviconURL>& candidates) {
NavigationEntry* entry = GetEntry();
if (!entry)
return;
- got_favicon_url_ = true;
+ 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;
- if (!favicon_expired_ && entry->favicon().is_valid() &&
- entry->favicon().url() == icon_url) {
- // We already have the icon, no need to proceed.
+ // For FAVICON.
+ if (current_candidate()->icon_type == ::FAVICON) {
+ if (!favicon_expired_ && entry->favicon().is_valid() &&
+ do_url_and_icon_match(*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() &&
+ do_url_and_icon_match(*current_candidate(),
+ history_icon_.icon_url, history_icon_.icon_type)) {
return;
}
- entry->favicon().set_url(icon_url);
-
if (got_favicon_from_history_)
- DownloadFaviconOrAskHistory(entry);
+ DownloadFaviconOrAskHistory(entry->url(), current_candidate()->icon_url,
+ ToHistoryIconType(current_candidate()->icon_type));
+}
+
+NavigationEntry* FaviconHelper::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 FaviconHelper::DownloadFavicon(const GURL& image_url, int image_size) {
+ return tab_contents()->render_view_host()->DownloadFavicon(image_url,
+ image_size);
+}
+
+void FaviconHelper::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 FaviconHelper::GetFavicon(
+ const GURL& icon_url,
+ history::IconType icon_type,
+ CancelableRequestConsumerBase* consumer,
+ FaviconService::FaviconDataCallback* callback) {
+ GetFaviconService()->GetFavicon(icon_url, icon_type, consumer, callback);
+}
+
+void FaviconHelper::GetFaviconForURL(
+ const GURL& page_url,
+ int icon_types,
+ CancelableRequestConsumerBase* consumer,
+ FaviconService::FaviconDataCallback* callback) {
+ GetFaviconService()->GetFaviconForURL(page_url, icon_types, consumer,
+ callback);
+}
+
+void FaviconHelper::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 FaviconHelper::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);
+}
+
+history::IconType FaviconHelper::ToHistoryIconType(IconType icon_type) {
+ switch (icon_type) {
+ case ::FAVICON:
+ return history::FAVICON;
+ case ::TOUCH_ICON:
+ return history::TOUCH_ICON;
+ case ::TOUCH_PRECOMPOSED_ICON:
+ return history::TOUCH_PRECOMPOSED_ICON;
+ case ::INVALID_ICON:
+ return history::INVALID_ICON;
+ }
+ NOTREACHED();
+ // Shouldn't reach here, just make compiler happy.
+ return history::INVALID_ICON;
}
bool FaviconHelper::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
+ bool message_handled = true;
IPC_BEGIN_MESSAGE_MAP(FaviconHelper, message)
- IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFaviconURL, OnUpdateFaviconURL)
IPC_MESSAGE_HANDLER(ViewHostMsg_DidDownloadFavicon, OnDidDownloadFavicon)
- IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_MESSAGE_UNHANDLED(message_handled = false)
IPC_END_MESSAGE_MAP()
- return handled;
+ return message_handled;
}
void FaviconHelper::OnDidDownloadFavicon(int id,
@@ -164,24 +276,23 @@ void FaviconHelper::OnDidDownloadFavicon(int id,
if (i->second.callback) {
i->second.callback->Run(id, errored, image);
- } else if (!errored) {
- SetFavicon(i->second.url, image_url, image);
+ } else if (current_candidate() &&
+ do_url_and_icon_match(*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 FaviconHelper,
+ // 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* FaviconHelper::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;
-}
-
void FaviconHelper::OnFaviconDataForInitialURL(
FaviconService::Handle handle,
history::FaviconData favicon) {
@@ -190,11 +301,14 @@ void FaviconHelper::OnFaviconDataForInitialURL(
return;
got_favicon_from_history_ = true;
+ history_icon_ = favicon;
favicon_expired_ = (favicon.known_icon && favicon.expired);
- if (favicon.known_icon && !entry->favicon().is_valid() &&
- (!got_favicon_url_ || entry->favicon().url() == favicon.icon_url)) {
+ if (favicon.known_icon && favicon.icon_type == history::FAVICON &&
+ !entry->favicon().is_valid() &&
+ (!current_candidate() || do_url_and_icon_match(*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
@@ -206,36 +320,39 @@ void FaviconHelper::OnFaviconDataForInitialURL(
}
if (favicon.known_icon && !favicon.expired) {
- if (got_favicon_url_ && entry->favicon().url() != favicon.icon_url) {
- // Mapping in the database is wrong. DownloadFaviconOrAskHistory will
+ if (current_candidate() && !do_url_and_icon_match(*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);
+ DownloadFaviconOrAskHistory(entry->url(), current_candidate()->icon_url,
+ static_cast<history::IconType>(current_candidate()->icon_type));
}
- } else if (got_favicon_url_) {
+ } 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);
+ 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 FaviconHelper::DownloadFaviconOrAskHistory(NavigationEntry* entry) {
- DCHECK(entry); // We should only get here if entry is valid.
+void FaviconHelper::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(entry->url(), entry->favicon().url(), kFaviconSize, NULL);
+ 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 (profile()->IsOffTheRecord()) {
- GetFaviconService()->GetFavicon(
- entry->favicon().url(),
- history::FAVICON,
- &cancelable_consumer_,
+ if (tab_contents()->profile()->IsOffTheRecord()) {
+ GetFavicon(icon_url, icon_type, &cancelable_consumer_,
NewCallback(this, &FaviconHelper::OnFaviconData));
} else {
// Ask the history service for the icon. This does two things:
@@ -244,50 +361,58 @@ void FaviconHelper::DownloadFaviconOrAskHistory(NavigationEntry* entry) {
// 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.
- GetFaviconService()->UpdateFaviconMappingAndFetch(
- entry->url(),
- entry->favicon().url(),
- history::FAVICON,
+ UpdateFaviconMappingAndFetch(page_url, icon_url, icon_type,
&cancelable_consumer_,
NewCallback(this, &FaviconHelper::OnFaviconData));
}
}
}
-void FaviconHelper::OnFaviconData(
- FaviconService::Handle handle,
- history::FaviconData favicon) {
+void FaviconHelper::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.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(), kFaviconSize, NULL);
+ 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 ||
+ !(do_url_and_icon_match(*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 FaviconHelper::ScheduleDownload(const GURL& url,
const GURL& image_url,
int image_size,
+ history::IconType icon_type,
ImageDownloadCallback* callback) {
- const int download_id = tab_contents()->render_view_host()->DownloadFavicon(
- image_url, image_size);
-
+ 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);
+ download_requests_[download_id] =
+ DownloadRequest(url, image_url, callback, icon_type);
}
return download_id;
@@ -304,12 +429,3 @@ SkBitmap FaviconHelper::ConvertToFaviconSize(const SkBitmap& image) {
}
return image;
}
-
-bool FaviconHelper::ShouldSaveFavicon(const GURL& url) {
- if (!profile()->IsOffTheRecord())
- return true;
-
- // Otherwise store the favicon if the page is bookmarked.
- BookmarkModel* bookmark_model = profile()->GetBookmarkModel();
- return bookmark_model && bookmark_model->IsBookmarked(url);
-}
diff --git a/chrome/browser/favicon_helper.h b/chrome/browser/favicon_helper.h
index 18722b0..288a204 100644
--- a/chrome/browser/favicon_helper.h
+++ b/chrome/browser/favicon_helper.h
@@ -12,10 +12,12 @@
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "chrome/browser/favicon_service.h"
+#include "chrome/common/icon_messages.h"
#include "chrome/common/ref_counted_util.h"
#include "content/browser/cancelable_request.h"
#include "content/browser/tab_contents/tab_contents_observer.h"
#include "googleurl/src/gurl.h"
+#include "ui/gfx/favicon_size.h"
class NavigationEntry;
class Profile;
@@ -67,7 +69,12 @@ class TabContents;
class FaviconHelper : public TabContentsObserver {
public:
- explicit FaviconHelper(TabContents* tab_contents);
+ enum Type {
+ FAVICON,
+ TOUCH,
+ };
+
+ FaviconHelper(TabContents* tab_contents, Type icon_type);
virtual ~FaviconHelper();
// Initiates loading the favicon for the specified url.
@@ -81,44 +88,92 @@ class FaviconHelper : public TabContentsObserver {
// 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,
+ 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 GURL& icon_url);
+ void OnUpdateFaviconURL(int32 page_id,
+ const std::vector<FaviconURL>& candidates);
+
+ protected:
+ // These virtual methods make FaviconHelper testable and are overridden by
+ // TestFaviconHelper
+ //
+ // 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 TestFaviconHelper; // For testing
+
struct DownloadRequest {
- DownloadRequest() : callback(NULL) {}
+ DownloadRequest();
+
DownloadRequest(const GURL& url,
const GURL& image_url,
- ImageDownloadCallback* callback)
- : url(url),
- image_url(image_url),
- callback(callback) {}
+ ImageDownloadCallback* callback,
+ history::IconType icon_type);
GURL url;
GURL image_url;
ImageDownloadCallback* callback;
+ history::IconType icon_type;
};
- // TabContentsObserver implementation.
- virtual bool OnMessageReceived(const IPC::Message& message);
+ static bool do_url_and_icon_match(const FaviconURL& favicon_url,
+ const GURL& url,
+ history::IconType icon_type) {
+ return favicon_url.icon_url == url &&
+ favicon_url.icon_type == static_cast<IconType>(icon_type);
+ }
+
+ // Returns history::IconType the given icon_type corresponds to.
+ static history::IconType ToHistoryIconType(IconType icon_type);
+
+ // TabContentsObserver overrides.
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
void OnDidDownloadFavicon(int id,
const GURL& image_url,
bool errored,
const SkBitmap& image);
- // 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.
- NavigationEntry* GetEntry();
-
- Profile* profile();
-
- FaviconService* GetFaviconService();
-
// See description above class for details.
void OnFaviconDataForInitialURL(FaviconService::Handle handle,
history::FaviconData favicon);
@@ -126,7 +181,9 @@ class FaviconHelper : public TabContentsObserver {
// 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(NavigationEntry* entry);
+ 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,
@@ -134,14 +191,21 @@ class FaviconHelper : public TabContentsObserver {
// 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,
+ int ScheduleDownload(const GURL& url,
+ const GURL& image_url,
+ int image_size,
+ history::IconType icon_type,
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);
+ void SetFavicon(const GURL& url,
+ const GURL& icon_url,
+ const SkBitmap& image,
+ history::IconType icon_type);
- // Converts the image data to an SkBitmap and sets it on the NavigationEntry.
+ // 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,
@@ -152,8 +216,19 @@ class FaviconHelper : public TabContentsObserver {
// wide. Does nothing if the image is empty.
SkBitmap ConvertToFaviconSize(const SkBitmap& image);
- // Returns true if the favicon should be saved.
- bool ShouldSaveFavicon(const GURL& url);
+ 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.
+ const int preferred_icon_size() {
+ return icon_types_ == history::FAVICON ? kFaviconSize : 0;
+ }
// Used for history requests.
CancelableRequestConsumer cancelable_consumer_;
@@ -161,10 +236,6 @@ class FaviconHelper : public TabContentsObserver {
// URL of the page we're requesting the favicon for.
GURL url_;
- // Whether we got the url for the page back from the renderer.
- // See "Favicon Details" in tab_contents.cc for more details.
- bool got_favicon_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_;
@@ -179,6 +250,18 @@ class FaviconHelper : public TabContentsObserver {
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_;
+
DISALLOW_COPY_AND_ASSIGN(FaviconHelper);
};
diff --git a/chrome/browser/favicon_helper_unittest.cc b/chrome/browser/favicon_helper_unittest.cc
new file mode 100644
index 0000000..732f7f4
--- /dev/null
+++ b/chrome/browser/favicon_helper_unittest.cc
@@ -0,0 +1,762 @@
+// 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_helper.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 TestFaviconHelper;
+
+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,
+ TestFaviconHelper* 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(FaviconHelper* 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_;
+ TestFaviconHelper* 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) {
+ }
+
+ 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 FaviconHelper's download and history request,
+// and also provide the methods to access the FaviconHelper internal.
+class TestFaviconHelper : public FaviconHelper {
+ public:
+ TestFaviconHelper(const GURL& page_url,
+ TabContents* tab_contents,
+ Type type)
+ : FaviconHelper(tab_contents, type),
+ download_image_size_(0),
+ download_id_(0),
+ tab_contents_(tab_contents){
+ entry_.set_url(page_url);
+ }
+
+ virtual ~TestFaviconHelper() {
+ }
+
+ 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) {
+ FaviconHelper::FetchFavicon(url);
+ }
+
+ // The methods to access favicon internal.
+ FaviconURL* current_candidate() {
+ return FaviconHelper::current_candidate();
+ }
+
+ void OnDidDownloadFavicon(int id,
+ const GURL& image_url,
+ bool errored,
+ const SkBitmap& image) {
+ FaviconHelper::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
+ // FaviconHelper.
+ int download_id_;
+
+ TabContents* tab_contents_;
+ scoped_ptr<DownloadHandler> download_handler_;
+ scoped_ptr<HistoryRequestHandler> history_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestFaviconHelper);
+};
+
+namespace {
+
+void DownloadHandler::UpdateFaviconURL(FaviconHelper* 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 FaviconHelperTest : public RenderViewHostTestHarness {
+};
+
+TEST_F(FaviconHelperTest, GetFaviconFromHistory) {
+ const GURL page_url("http://www.google.com");
+ const GURL icon_url("http://www.google.com/favicon");
+
+ TestFaviconHelper helper(page_url, contents(), FaviconHelper::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 FaviconHelper 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, FAVICON));
+ DownloadHandler::UpdateFaviconURL(&helper, urls);
+
+ // Verify FaviconHelper status
+ EXPECT_EQ(1U, helper.urls().size());
+ ASSERT_TRUE(helper.current_candidate());
+ ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
+ ASSERT_EQ(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(FaviconHelperTest, DownloadFavicon) {
+ const GURL page_url("http://www.google.com");
+ const GURL icon_url("http://www.google.com/favicon");
+
+ TestFaviconHelper helper(page_url, contents(), FaviconHelper::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 FaviconHelper 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, FAVICON));
+ DownloadHandler::UpdateFaviconURL(&helper, urls);
+
+ // Verify FaviconHelper status
+ EXPECT_EQ(1U, helper.urls().size());
+ ASSERT_TRUE(helper.current_candidate());
+ ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
+ ASSERT_EQ(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(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(FaviconHelperTest, 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");
+
+ TestFaviconHelper helper(page_url, contents(), FaviconHelper::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 FaviconHelper 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, FAVICON));
+ DownloadHandler::UpdateFaviconURL(&helper, urls);
+
+ // Verify FaviconHelper status.
+ EXPECT_EQ(1U, helper.urls().size());
+ ASSERT_TRUE(helper.current_candidate());
+ ASSERT_EQ(new_icon_url, helper.current_candidate()->icon_url);
+ ASSERT_EQ(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(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(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(FaviconHelperTest, 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");
+
+ TestFaviconHelper helper(page_url, contents(), FaviconHelper::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 FaviconHelper 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, FAVICON));
+ DownloadHandler::UpdateFaviconURL(&helper, urls);
+
+ // Verify FaviconHelper status.
+ EXPECT_EQ(1U, helper.urls().size());
+ ASSERT_TRUE(helper.current_candidate());
+ ASSERT_EQ(new_icon_url, helper.current_candidate()->icon_url);
+ ASSERT_EQ(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(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(FaviconHelperTest, 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");
+
+ TestFaviconHelper helper(page_url, contents(), FaviconHelper::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 FaviconHelper 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, TOUCH_PRECOMPOSED_ICON));
+ urls.push_back(FaviconURL(new_icon_url, TOUCH_ICON));
+ urls.push_back(FaviconURL(new_icon_url, FAVICON));
+
+ DownloadHandler::UpdateFaviconURL(&helper, urls);
+
+ // Verify FaviconHelper status.
+ EXPECT_EQ(2U, helper.urls().size());
+ ASSERT_TRUE(helper.current_candidate());
+ ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
+ ASSERT_EQ(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(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(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(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(TOUCH_ICON, history_handler->icon_type_);
+ EXPECT_LT(0U, history_handler->image_data_.size());
+ EXPECT_EQ(page_url, history_handler->page_url_);
+}
+
+TEST_F(FaviconHelperTest, 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");
+
+ TestFaviconHelper helper(page_url, contents(), FaviconHelper::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 FaviconHelper 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, TOUCH_PRECOMPOSED_ICON));
+ urls.push_back(FaviconURL(new_icon_url, TOUCH_ICON));
+ urls.push_back(FaviconURL(new_icon_url, FAVICON));
+
+ DownloadHandler::UpdateFaviconURL(&helper, urls);
+
+ // Verify FaviconHelper status.
+ EXPECT_EQ(2U, helper.urls().size());
+ ASSERT_TRUE(helper.current_candidate());
+ ASSERT_EQ(icon_url, helper.current_candidate()->icon_url);
+ ASSERT_EQ(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(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, 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(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(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_;
+ 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/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index c142f15..6051d07 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -448,9 +448,18 @@ void PrerenderContents::OnDidRedirectProvisionalLoad(int32 page_id,
Destroy(FINAL_STATUS_HTTPS);
}
-void PrerenderContents::OnUpdateFaviconURL(int32 page_id,
- const GURL& icon_url) {
- icon_url_ = icon_url;
+void PrerenderContents::OnUpdateFaviconURL(
+ int32 page_id,
+ const std::vector<FaviconURL>& urls) {
+ LOG(INFO) << "PrerenderContents::OnUpdateFaviconURL" << icon_url_;
+ for (std::vector<FaviconURL>::const_iterator i = urls.begin();
+ i != urls.end(); ++i) {
+ if (i->icon_type == FAVICON) {
+ icon_url_ = i->icon_url;
+ LOG(INFO) << icon_url_;
+ return;
+ }
+ }
}
void PrerenderContents::OnMaybeCancelPrerender(
diff --git a/chrome/browser/prerender/prerender_contents.h b/chrome/browser/prerender/prerender_contents.h
index 2e331f5..ad94e14 100644
--- a/chrome/browser/prerender/prerender_contents.h
+++ b/chrome/browser/prerender/prerender_contents.h
@@ -14,6 +14,7 @@
#include "chrome/browser/prerender/prerender_final_status.h"
#include "chrome/browser/tab_contents/render_view_host_delegate_helper.h"
#include "chrome/browser/ui/app_modal_dialogs/js_modal_dialog.h"
+#include "chrome/common/icon_messages.h"
#include "chrome/common/prerender_constants.h"
#include "chrome/common/view_types.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
@@ -211,7 +212,7 @@ class PrerenderContents : public RenderViewHostDelegate,
const GURL& source_url,
const GURL& target_url);
- void OnUpdateFaviconURL(int32 page_id, const GURL& icon_url);
+ void OnUpdateFaviconURL(int32 page_id, const std::vector<FaviconURL>& urls);
void OnMaybeCancelPrerender(PrerenderCancellationReason reason);
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index 4246d8f..3b9e158 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -337,8 +337,12 @@ bool PrerenderManager::MaybeUsePreloadedPage(TabContents* tc, const GURL& url) {
tc->UpdateTitle(rvh, pc->page_id(), UTF16ToWideHack(title));
GURL icon_url = pc->icon_url();
- if (!icon_url.is_empty())
- tc->favicon_helper().OnUpdateFaviconURL(pc->page_id(), icon_url);
+ if (!icon_url.is_empty()) {
+ LOG(INFO) << "MaybeUsePreloadedPage";
+ std::vector<FaviconURL> urls;
+ urls.push_back(FaviconURL(icon_url, FAVICON));
+ tc->favicon_helper().OnUpdateFaviconURL(pc->page_id(), urls);
+ }
if (pc->has_stopped_loading())
tc->DidStopLoading();
diff --git a/chrome/browser/ui/views/create_application_shortcut_view.cc b/chrome/browser/ui/views/create_application_shortcut_view.cc
index 2b3824a..ed74f5f 100644
--- a/chrome/browser/ui/views/create_application_shortcut_view.cc
+++ b/chrome/browser/ui/views/create_application_shortcut_view.cc
@@ -457,6 +457,7 @@ void CreateUrlApplicationShortcutView::FetchIcon() {
unprocessed_icons_.back().url,
std::max(unprocessed_icons_.back().width,
unprocessed_icons_.back().height),
+ history::FAVICON,
NewCallback(pending_download_, &IconDownloadCallbackFunctor::Run));
unprocessed_icons_.pop_back();
diff --git a/chrome/browser/ui/web_applications/web_app_ui.cc b/chrome/browser/ui/web_applications/web_app_ui.cc
index 7556105..6c1480a 100644
--- a/chrome/browser/ui/web_applications/web_app_ui.cc
+++ b/chrome/browser/ui/web_applications/web_app_ui.cc
@@ -137,6 +137,7 @@ void UpdateShortcutWorker::DownloadIcon() {
unprocessed_icons_.back().url,
std::max(unprocessed_icons_.back().width,
unprocessed_icons_.back().height),
+ history::FAVICON,
NewCallback(this, &UpdateShortcutWorker::OnIconDownloaded));
unprocessed_icons_.pop_back();
}
diff --git a/chrome/browser/ui/webui/most_visited_handler.cc b/chrome/browser/ui/webui/most_visited_handler.cc
index 11f6e1b..99bac17 100644
--- a/chrome/browser/ui/webui/most_visited_handler.cc
+++ b/chrome/browser/ui/webui/most_visited_handler.cc
@@ -27,6 +27,7 @@
#include "chrome/browser/ui/webui/new_tab_ui.h"
#include "chrome/browser/ui/webui/thumbnail_source.h"
#include "chrome/common/pref_names.h"
+#include "chrome/common/url_constants.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_source.h"
#include "content/common/notification_type.h"
@@ -68,8 +69,7 @@ WebUIMessageHandler* MostVisitedHandler::Attach(WebUI* web_ui) {
ThumbnailSource* thumbnail_src = new ThumbnailSource(profile);
profile->GetChromeURLDataManager()->AddDataSource(thumbnail_src);
- FaviconSource* favicon_src = new FaviconSource(profile);
- profile->GetChromeURLDataManager()->AddDataSource(favicon_src);
+ profile->GetChromeURLDataManager()->AddDataSource(new FaviconSource(profile));
// Get notifications when history is cleared.
registrar_.Add(this, NotificationType::HISTORY_URLS_DELETED,
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 8a26eed..bf8cba0 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -51,6 +51,8 @@
'common/guid.h',
'common/guid_posix.cc',
'common/guid_win.cc',
+ 'common/icon_messages.cc',
+ 'common/icon_messages.h',
'common/instant_types.h',
'common/logging_chrome.cc',
'common/logging_chrome.h',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 5bc01a4..865b5b2 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1344,6 +1344,7 @@
'browser/extensions/sandboxed_extension_unpacker_unittest.cc',
'browser/extensions/user_script_listener_unittest.cc',
'browser/extensions/user_script_master_unittest.cc',
+ 'browser/favicon_helper_unittest.cc',
'browser/first_run/first_run_unittest.cc',
'browser/geolocation/geolocation_content_settings_map_unittest.cc',
'browser/geolocation/geolocation_exceptions_table_model_unittest.cc',
diff --git a/chrome/common/icon_messages.cc b/chrome/common/icon_messages.cc
new file mode 100644
index 0000000..7648c14
--- /dev/null
+++ b/chrome/common/icon_messages.cc
@@ -0,0 +1,60 @@
+// 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/common/icon_messages.h"
+
+#include "content/common/common_param_traits.h"
+
+FaviconURL::FaviconURL()
+ : icon_type(INVALID_ICON) {
+}
+
+FaviconURL::FaviconURL(const GURL& url, IconType type)
+ : icon_url(url),
+ icon_type(type) {
+}
+
+FaviconURL::~FaviconURL() {
+}
+
+namespace IPC {
+
+// static
+void ParamTraits<IconType>::Write(Message* m, const param_type& p) {
+ m->WriteInt(p);
+}
+
+// static
+bool ParamTraits<IconType>::Read(const Message* m, void** iter, param_type* p) {
+ int type;
+ if (!m->ReadInt(iter, &type))
+ return false;
+ *p = static_cast<IconType>(type);
+ return true;
+}
+
+// static
+void ParamTraits<IconType>::Log(const param_type& p, std::string* l) {
+ l->append("IconType");
+}
+
+// static
+void ParamTraits<FaviconURL>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.icon_url);
+ WriteParam(m, p.icon_type);
+}
+
+// static
+bool ParamTraits<FaviconURL>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ return ReadParam(m, iter, &p->icon_url) && ReadParam(m, iter, &p->icon_type);
+}
+
+// static
+void ParamTraits<FaviconURL>::Log(const param_type& p, std::string* l) {
+ l->append("<FaviconURL>");
+}
+
+} // namespace IPC
diff --git a/chrome/common/icon_messages.h b/chrome/common/icon_messages.h
new file mode 100644
index 0000000..47d4e9f
--- /dev/null
+++ b/chrome/common/icon_messages.h
@@ -0,0 +1,57 @@
+// 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.
+
+// Multiply-included message file, no traditional include guard.
+#include "googleurl/src/gurl.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_param_traits.h"
+
+// TODO : Pull ViewHostMsg_UpdateFaviconURL into this file
+
+#ifndef CHROME_COMMON_ICON_MESSAGES_H__
+#define CHROME_COMMON_ICON_MESSAGES_H__
+
+// The icon type in a page. The definition must be same as history::IconType.
+enum IconType {
+ INVALID_ICON = 0x0,
+ FAVICON = 1 << 0,
+ TOUCH_ICON = 1 << 1,
+ TOUCH_PRECOMPOSED_ICON = 1 << 2
+};
+
+// The favicon url from the render.
+struct FaviconURL {
+ FaviconURL();
+ FaviconURL(const GURL& url, IconType type);
+ ~FaviconURL();
+
+ // The url of the icon.
+ GURL icon_url;
+
+ // The type of the icon
+ IconType icon_type;
+};
+
+namespace IPC {
+
+template <>
+struct ParamTraits<IconType> {
+ typedef IconType param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<FaviconURL> {
+ typedef FaviconURL param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+} // namespace IPC
+
+#endif // CHROME_COMMON_ICON_MESSAGES_H__
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index ba64142..d417048 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -18,6 +18,7 @@
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/common/content_settings.h"
+#include "chrome/common/icon_messages.h"
#include "chrome/common/instant_types.h"
#include "chrome/common/nacl_types.h"
#include "chrome/common/prerender_constants.h"
@@ -334,10 +335,10 @@ IPC_MESSAGE_ROUTED3(ViewHostMsg_Thumbnail,
IPC_MESSAGE_ROUTED1(ViewHostMsg_Snapshot,
SkBitmap /* bitmap */)
-// Notification that the url for the favicon of a site has been determined.
+// Notification that the urls for the favicon of a site has been determined.
IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateFaviconURL,
int32 /* page_id */,
- GURL /* url of the favicon */)
+ std::vector<FaviconURL> /* urls of the favicon */)
// Following message is used to communicate the values received by the
// callback binding the JS to Cpp.
diff --git a/content/browser/tab_contents/tab_contents.cc b/content/browser/tab_contents/tab_contents.cc
index 26aa66a..6e5fe75 100644
--- a/content/browser/tab_contents/tab_contents.cc
+++ b/content/browser/tab_contents/tab_contents.cc
@@ -371,7 +371,9 @@ TabContents::~TabContents() {
}
void TabContents::AddObservers() {
- favicon_helper_.reset(new FaviconHelper(this));
+ favicon_helper_.reset(new FaviconHelper(this, FaviconHelper::FAVICON));
+ if (browser_defaults::kEnableTouchIcon)
+ touch_icon_helper_.reset(new FaviconHelper(this, FaviconHelper::TOUCH));
plugin_observer_.reset(new PluginObserver(this));
safebrowsing_detection_host_.reset(new safe_browsing::ClientSideDetectionHost(
this));
@@ -410,6 +412,7 @@ bool TabContents::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ViewHostMsg_GoToEntryAtOffset, OnGoToEntryAtOffset)
IPC_MESSAGE_HANDLER(ViewHostMsg_PageContents, OnPageContents)
IPC_MESSAGE_HANDLER(ViewHostMsg_PageTranslated, OnPageTranslated)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFaviconURL, OnUpdateFaviconURL)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP_EX()
@@ -1534,6 +1537,9 @@ void TabContents::DidNavigateMainFramePostCommit(
// Get the favicon, either from history or request it from the net.
favicon_helper_->FetchFavicon(details.entry->url());
+ if (touch_icon_helper_.get())
+ touch_icon_helper_->FetchFavicon(details.entry->url());
+
// Clear all page actions, blocked content notifications and browser actions
// for this tab, unless this is an in-page navigation.
if (!details.is_in_page) {
@@ -2405,6 +2411,14 @@ void TabContents::RequestDesktopNotificationPermission(
render_view_host()->routing_id(), callback_context, this);
}
+void TabContents::OnUpdateFaviconURL(
+ int32 page_id,
+ const std::vector<FaviconURL>& candidates) {
+ favicon_helper().OnUpdateFaviconURL(page_id, candidates);
+ if (touch_icon_helper_.get())
+ touch_icon_helper_->OnUpdateFaviconURL(page_id, candidates);
+}
+
void TabContents::BeforeUnloadFiredFromRenderManager(
bool proceed,
bool* proceed_to_fire_unload) {
diff --git a/content/browser/tab_contents/tab_contents.h b/content/browser/tab_contents/tab_contents.h
index 4f62795d..3411d32 100644
--- a/content/browser/tab_contents/tab_contents.h
+++ b/content/browser/tab_contents/tab_contents.h
@@ -883,6 +883,8 @@ class TabContents : public PageNavigator,
virtual void RequestDesktopNotificationPermission(const GURL& source_origin,
int callback_context);
+ void OnUpdateFaviconURL(int32 page_id,
+ const std::vector<FaviconURL>& candidates);
// RenderViewHostManager::Delegate -------------------------------------------
// Blocks/unblocks interaction with renderer process.
@@ -962,6 +964,10 @@ class TabContents : public PageNavigator,
// Handles downloading favicons.
scoped_ptr<FaviconHelper> favicon_helper_;
+ // Handles downloading touchicons. It is NULL if
+ // browser_defaults::kEnableTouchIcon is false.
+ scoped_ptr<FaviconHelper> touch_icon_helper_;
+
// RenderViewHost::ContentSettingsDelegate.
scoped_ptr<TabSpecificContentSettings> content_settings_delegate_;
diff --git a/content/renderer/render_view.cc b/content/renderer/render_view.cc
index 6052063..0655bd6 100644
--- a/content/renderer/render_view.cc
+++ b/content/renderer/render_view.cc
@@ -2010,9 +2010,14 @@ void RenderView::didStopLoading() {
// displayed when done loading. Ideally we would send notification when
// finished parsing the head, but webkit doesn't support that yet.
// The feed discovery code would also benefit from access to the head.
+
+ // TODO : Get both favicon and touch icon url, and send them to the browser.
GURL favicon_url(webview()->mainFrame()->favIconURL());
- if (!favicon_url.is_empty())
- Send(new ViewHostMsg_UpdateFaviconURL(routing_id_, page_id_, favicon_url));
+ if (!favicon_url.is_empty()) {
+ std::vector<FaviconURL> urls;
+ urls.push_back(FaviconURL(favicon_url, FAVICON));
+ Send(new ViewHostMsg_UpdateFaviconURL(routing_id_, page_id_, urls));
+ }
AddGURLSearchProvider(webview()->mainFrame()->openSearchDescriptionURL(),
search_provider::AUTODETECTED_PROVIDER);
@@ -3147,10 +3152,9 @@ void RenderView::didReceiveTitle(WebFrame* frame, const WebString& title) {
void RenderView::didChangeIcons(WebFrame* frame) {
if (!frame->parent()) {
- Send(new ViewHostMsg_UpdateFaviconURL(
- routing_id_,
- page_id_,
- frame->favIconURL()));
+ std::vector<FaviconURL> urls;
+ urls.push_back(FaviconURL(frame->favIconURL(), FAVICON));
+ Send(new ViewHostMsg_UpdateFaviconURL(routing_id_, page_id_, urls));
}
}