| Index: chrome/browser/favicon_helper.cc
|
| diff --git a/chrome/browser/favicon_helper.cc b/chrome/browser/favicon_helper.cc
|
| index 1e5206b4c9eed6628f4ce99d2e153b832e5808f8..6479c697be28c809506f6f629b28d987056605cd 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);
|
| -}
|
|
|