diff options
author | michaelbai@google.com <michaelbai@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-11 21:40:46 +0000 |
---|---|---|
committer | michaelbai@google.com <michaelbai@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-11 21:40:46 +0000 |
commit | 351ef3bc6f4ef78a1a8a5e9ccf2bdf0e3ec38e65 (patch) | |
tree | 15756795df3c94317f518cda23697ccacadea46a | |
parent | 639e57d0e1d79f996733d81285c6604314ca9cde (diff) | |
download | chromium_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.cc | 2 | ||||
-rw-r--r-- | chrome/browser/defaults.h | 5 | ||||
-rw-r--r-- | chrome/browser/favicon_helper.cc | 310 | ||||
-rw-r--r-- | chrome/browser/favicon_helper.h | 139 | ||||
-rw-r--r-- | chrome/browser/favicon_helper_unittest.cc | 762 | ||||
-rw-r--r-- | chrome/browser/prerender/prerender_contents.cc | 15 | ||||
-rw-r--r-- | chrome/browser/prerender/prerender_contents.h | 3 | ||||
-rw-r--r-- | chrome/browser/prerender/prerender_manager.cc | 8 | ||||
-rw-r--r-- | chrome/browser/ui/views/create_application_shortcut_view.cc | 1 | ||||
-rw-r--r-- | chrome/browser/ui/web_applications/web_app_ui.cc | 1 | ||||
-rw-r--r-- | chrome/browser/ui/webui/most_visited_handler.cc | 4 | ||||
-rw-r--r-- | chrome/chrome_common.gypi | 2 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 1 | ||||
-rw-r--r-- | chrome/common/icon_messages.cc | 60 | ||||
-rw-r--r-- | chrome/common/icon_messages.h | 57 | ||||
-rw-r--r-- | chrome/common/render_messages.h | 5 | ||||
-rw-r--r-- | content/browser/tab_contents/tab_contents.cc | 16 | ||||
-rw-r--r-- | content/browser/tab_contents/tab_contents.h | 6 | ||||
-rw-r--r-- | content/renderer/render_view.cc | 16 |
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)); } } |