summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/favicon/favicon_handler_unittest.cc31
-rw-r--r--chrome/browser/favicon/favicon_tab_helper.cc336
-rw-r--r--chrome/browser/favicon/favicon_tab_helper.h139
-rw-r--r--chrome/browser/favicon/favicon_tab_helper_browsertest.cc7
-rw-r--r--chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm4
-rw-r--r--chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc3
-rw-r--r--components/favicon.gypi15
-rw-r--r--components/favicon/DEPS1
-rw-r--r--components/favicon/content/BUILD.gn4
-rw-r--r--components/favicon/content/content_favicon_driver.cc182
-rw-r--r--components/favicon/content/content_favicon_driver.h88
-rw-r--r--components/favicon/core/BUILD.gn5
-rw-r--r--components/favicon/core/favicon_driver.cc35
-rw-r--r--components/favicon/core/favicon_driver.h51
-rw-r--r--components/favicon/core/favicon_driver_impl.cc178
-rw-r--r--components/favicon/core/favicon_driver_impl.h98
-rw-r--r--components/favicon/core/favicon_handler.cc5
-rw-r--r--components/favicon/core/favicon_handler.h6
-rw-r--r--components/favicon/ios/web_favicon_driver.cc122
-rw-r--r--components/favicon/ios/web_favicon_driver.h66
20 files changed, 906 insertions, 470 deletions
diff --git a/chrome/browser/favicon/favicon_handler_unittest.cc b/chrome/browser/favicon/favicon_handler_unittest.cc
index 5a70ff4..e01f585 100644
--- a/chrome/browser/favicon/favicon_handler_unittest.cc
+++ b/chrome/browser/favicon/favicon_handler_unittest.cc
@@ -183,6 +183,35 @@ class TestFaviconDriver : public favicon::FaviconDriver {
~TestFaviconDriver() override {}
+ // favicon::FaviconDriver implementation.
+ void FetchFavicon(const GURL& url) override {
+ ADD_FAILURE() << "TestFaviconDriver::FetchFavicon() "
+ << "should never be called in tests.";
+ }
+
+ void SaveFavicon() override {
+ ADD_FAILURE() << "TestFaviconDriver::SaveFavicon() "
+ << "should never be called in tests.";
+ }
+
+ gfx::Image GetFavicon() const override {
+ ADD_FAILURE() << "TestFaviconDriver::GetFavicon() "
+ << "should never be called in tests.";
+ return gfx::Image();
+ }
+
+ bool FaviconIsValid() const override {
+ ADD_FAILURE() << "TestFaviconDriver::FaviconIsValid() "
+ << "should never be called in tests.";
+ return false;
+ }
+
+ bool HasPendingTasksForTest() override {
+ ADD_FAILURE() << "TestFaviconDriver::HasPendingTasksForTest() "
+ << "should never be called in tests.";
+ return false;
+ }
+
int StartDownload(const GURL& url, int max_bitmap_size) override {
ADD_FAILURE() << "TestFaviconDriver::StartDownload() "
<< "should never be called in tests.";
@@ -231,8 +260,6 @@ class TestFaviconDriver : public favicon::FaviconDriver {
SetActiveFaviconImage(image);
}
- void NotifyFaviconUpdated(bool icon_url_changed) override {}
-
size_t num_active_favicon() const { return num_active_favicon_; }
size_t num_favicon_available() const { return num_favicon_available_; }
void ResetNumActiveFavicon() { num_active_favicon_ = 0; }
diff --git a/chrome/browser/favicon/favicon_tab_helper.cc b/chrome/browser/favicon/favicon_tab_helper.cc
index e5e9334..177e7ba 100644
--- a/chrome/browser/favicon/favicon_tab_helper.cc
+++ b/chrome/browser/favicon/favicon_tab_helper.cc
@@ -4,73 +4,13 @@
#include "chrome/browser/favicon/favicon_tab_helper.h"
-#include "base/command_line.h"
-#include "base/metrics/field_trial.h"
-#include "base/strings/string_util.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
-#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/favicon/favicon_service_factory.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search/search.h"
-#include "chrome/common/chrome_constants.h"
#include "chrome/common/url_constants.h"
-#include "components/bookmarks/browser/bookmark_model.h"
-#include "components/favicon/content/favicon_url_util.h"
-#include "components/favicon/core/favicon_driver_observer.h"
-#include "components/favicon/core/favicon_handler.h"
-#include "components/favicon/core/favicon_service.h"
-#include "components/favicon_base/favicon_types.h"
-#include "components/history/core/browser/history_service.h"
-#include "content/public/browser/favicon_status.h"
-#include "content/public/browser/invalidate_type.h"
-#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_details.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/favicon_url.h"
-#include "ui/base/ui_base_switches.h"
-#include "ui/gfx/codec/png_codec.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/image/image_skia_rep.h"
-
-using content::FaviconStatus;
-using content::NavigationController;
-using content::NavigationEntry;
-using content::WebContents;
-
-DEFINE_WEB_CONTENTS_USER_DATA_KEY(FaviconTabHelper);
-
-namespace {
-
-// Returns whether icon NTP is enabled by experiment.
-// TODO(huangs): Remove all 3 copies of this routine once Icon NTP launches.
-bool IsIconNTPEnabled() {
- // Note: It's important to query the field trial state first, to ensure that
- // UMA reports the correct group.
- const std::string group_name = base::FieldTrialList::FindFullName("IconNTP");
- using base::CommandLine;
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableIconNtp))
- return false;
- if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableIconNtp))
- return true;
-
- return StartsWithASCII(group_name, "Enabled", true);
-}
-
-#if defined(OS_ANDROID) || defined(OS_IOS)
-const bool kDownloadLargestIcon = true;
-const bool kEnableTouchIcon = true;
-#else
-const bool kDownloadLargestIcon = false;
-const bool kEnableTouchIcon = false;
-#endif
-
-} // namespace
// static
void FaviconTabHelper::CreateForWebContents(
@@ -93,277 +33,41 @@ void FaviconTabHelper::CreateForWebContents(
BookmarkModelFactory::GetForProfileIfExists(original_profile)));
}
-FaviconTabHelper::FaviconTabHelper(WebContents* web_contents,
- favicon::FaviconService* favicon_service,
- history::HistoryService* history_service,
- bookmarks::BookmarkModel* bookmark_model)
- : content::WebContentsObserver(web_contents),
- favicon_service_(favicon_service),
- history_service_(history_service),
- bookmark_model_(bookmark_model) {
- favicon_handler_.reset(new favicon::FaviconHandler(
- favicon_service_, this, favicon::FaviconHandler::FAVICON,
- kDownloadLargestIcon));
- if (kEnableTouchIcon) {
- touch_icon_handler_.reset(new favicon::FaviconHandler(
- favicon_service_, this, favicon::FaviconHandler::TOUCH,
- kDownloadLargestIcon));
- }
- if (IsIconNTPEnabled()) {
- large_icon_handler_.reset(new favicon::FaviconHandler(
- favicon_service_, this, favicon::FaviconHandler::LARGE, true));
- }
-}
-
-FaviconTabHelper::~FaviconTabHelper() {
-}
-
-void FaviconTabHelper::FetchFavicon(const GURL& url) {
- favicon_handler_->FetchFavicon(url);
- if (touch_icon_handler_.get())
- touch_icon_handler_->FetchFavicon(url);
- if (large_icon_handler_.get())
- large_icon_handler_->FetchFavicon(url);
-}
-
-gfx::Image FaviconTabHelper::GetFavicon() const {
- // Like GetTitle(), we also want to use the favicon for the last committed
- // entry rather than a pending navigation entry.
- const NavigationController& controller = web_contents()->GetController();
- NavigationEntry* entry = controller.GetTransientEntry();
- if (entry)
- return entry->GetFavicon().image;
-
- entry = controller.GetLastCommittedEntry();
- if (entry)
- return entry->GetFavicon().image;
- return gfx::Image();
-}
-
-bool FaviconTabHelper::FaviconIsValid() const {
- const NavigationController& controller = web_contents()->GetController();
- NavigationEntry* entry = controller.GetTransientEntry();
- if (entry)
- return entry->GetFavicon().valid;
-
- entry = controller.GetLastCommittedEntry();
- if (entry)
- return entry->GetFavicon().valid;
-
- return false;
+// static
+FaviconTabHelper* FaviconTabHelper::FromWebContents(
+ content::WebContents* web_contents) {
+ return static_cast<FaviconTabHelper*>(
+ favicon::ContentFaviconDriver::FromWebContents(web_contents));
}
-bool FaviconTabHelper::ShouldDisplayFavicon() {
+// static
+bool FaviconTabHelper::ShouldDisplayFavicon(
+ content::WebContents* web_contents) {
// Always display a throbber during pending loads.
- const NavigationController& controller = web_contents()->GetController();
+ const content::NavigationController& controller =
+ web_contents->GetController();
if (controller.GetLastCommittedEntry() && controller.GetPendingEntry())
return true;
- GURL url = web_contents()->GetURL();
+ GURL url = web_contents->GetURL();
if (url.SchemeIs(content::kChromeUIScheme) &&
url.host() == chrome::kChromeUINewTabHost) {
return false;
}
// No favicon on Instant New Tab Pages.
- if (chrome::IsInstantNTP(web_contents()))
+ if (chrome::IsInstantNTP(web_contents))
return false;
return true;
}
-void FaviconTabHelper::SaveFavicon() {
- GURL active_url = GetActiveURL();
- if (active_url.is_empty())
- return;
-
- // Make sure the page is in history, otherwise adding the favicon does
- // nothing.
- if (!history_service_)
- return;
- history_service_->AddPageNoVisitForBookmark(active_url, GetActiveTitle());
-
- if (!favicon_service_)
- return;
- if (!GetActiveFaviconValidity())
- return;
- GURL favicon_url = GetActiveFaviconURL();
- if (favicon_url.is_empty())
- return;
- gfx::Image image = GetActiveFaviconImage();
- if (image.IsEmpty())
- return;
- favicon_service_->SetFavicons(active_url, favicon_url, favicon_base::FAVICON,
- image);
-}
-
-void FaviconTabHelper::AddObserver(favicon::FaviconDriverObserver* observer) {
- observer_list_.AddObserver(observer);
-}
-
-void FaviconTabHelper::RemoveObserver(
- favicon::FaviconDriverObserver* observer) {
- observer_list_.RemoveObserver(observer);
-}
-
-int FaviconTabHelper::StartDownload(const GURL& url, int max_image_size) {
- if (favicon_service_ && favicon_service_->WasUnableToDownloadFavicon(url)) {
- DVLOG(1) << "Skip Failed FavIcon: " << url;
- return 0;
- }
-
- bool bypass_cache = (bypass_cache_page_url_ == GetActiveURL());
- bypass_cache_page_url_ = GURL();
-
- return web_contents()->DownloadImage(
- url, true, max_image_size, bypass_cache,
- base::Bind(&FaviconTabHelper::DidDownloadFavicon,
- base::Unretained(this)));
-}
-
-bool FaviconTabHelper::IsOffTheRecord() {
- DCHECK(web_contents());
- return web_contents()->GetBrowserContext()->IsOffTheRecord();
-}
-
-bool FaviconTabHelper::IsBookmarked(const GURL& url) {
- return bookmark_model_ && bookmark_model_->IsBookmarked(url);
-}
-
-GURL FaviconTabHelper::GetActiveURL() {
- NavigationEntry* entry = web_contents()->GetController().GetActiveEntry();
- return entry ? entry->GetURL() : GURL();
-}
-
-base::string16 FaviconTabHelper::GetActiveTitle() {
- NavigationEntry* entry = web_contents()->GetController().GetActiveEntry();
- return entry ? entry->GetTitle() : base::string16();
-}
-
-bool FaviconTabHelper::GetActiveFaviconValidity() {
- return GetFaviconStatus().valid;
-}
-
-void FaviconTabHelper::SetActiveFaviconValidity(bool valid) {
- GetFaviconStatus().valid = valid;
-}
-
-GURL FaviconTabHelper::GetActiveFaviconURL() {
- return GetFaviconStatus().url;
-}
-
-void FaviconTabHelper::SetActiveFaviconURL(const GURL& url) {
- GetFaviconStatus().url = url;
-}
-
-gfx::Image FaviconTabHelper::GetActiveFaviconImage() {
- return GetFaviconStatus().image;
-}
-
-void FaviconTabHelper::SetActiveFaviconImage(const gfx::Image& image) {
- GetFaviconStatus().image = image;
-}
-
-void FaviconTabHelper::OnFaviconAvailable(const gfx::Image& image,
- const GURL& icon_url,
- bool is_active_favicon) {
- if (is_active_favicon) {
- bool icon_url_changed = GetActiveFaviconURL() != icon_url;
- // No matter what happens, we need to mark the favicon as being set.
- SetActiveFaviconValidity(true);
- SetActiveFaviconURL(icon_url);
-
- if (image.IsEmpty())
- return;
-
- SetActiveFaviconImage(image);
- NotifyFaviconUpdated(icon_url_changed);
- }
- if (!image.IsEmpty()) {
- FOR_EACH_OBSERVER(favicon::FaviconDriverObserver, observer_list_,
- OnFaviconAvailable(image));
- }
-}
-
-void FaviconTabHelper::NotifyFaviconUpdated(bool icon_url_changed) {
- FOR_EACH_OBSERVER(favicon::FaviconDriverObserver, observer_list_,
- OnFaviconUpdated(this, icon_url_changed));
- web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
-}
-
-void FaviconTabHelper::DidDownloadFavicon(
- int id,
- int http_status_code,
- const GURL& image_url,
- const std::vector<SkBitmap>& bitmaps,
- const std::vector<gfx::Size>& original_bitmap_sizes) {
- if (bitmaps.empty() && http_status_code == 404) {
- DVLOG(1) << "Failed to Download Favicon:" << image_url;
- if (favicon_service_)
- favicon_service_->UnableToDownloadFavicon(image_url);
- }
-
- favicon_handler_->OnDidDownloadFavicon(id, image_url, bitmaps,
- original_bitmap_sizes);
- if (touch_icon_handler_.get()) {
- touch_icon_handler_->OnDidDownloadFavicon(id, image_url, bitmaps,
- original_bitmap_sizes);
- }
- if (large_icon_handler_.get()) {
- large_icon_handler_->OnDidDownloadFavicon(id, image_url, bitmaps,
- original_bitmap_sizes);
- }
-}
-
-content::FaviconStatus& FaviconTabHelper::GetFaviconStatus() {
- DCHECK(web_contents()->GetController().GetActiveEntry());
- return web_contents()->GetController().GetActiveEntry()->GetFavicon();
-}
-
-void FaviconTabHelper::DidStartNavigationToPendingEntry(
- const GURL& url,
- NavigationController::ReloadType reload_type) {
- if (reload_type == NavigationController::NO_RELOAD || IsOffTheRecord())
- return;
-
- bypass_cache_page_url_ = url;
-
- if (favicon_service_) {
- favicon_service_->SetFaviconOutOfDateForPage(url);
- if (reload_type == NavigationController::RELOAD_IGNORING_CACHE)
- favicon_service_->ClearUnableToDownloadFavicons();
- }
-}
-
-void FaviconTabHelper::DidNavigateMainFrame(
- const content::LoadCommittedDetails& details,
- const content::FrameNavigateParams& params) {
- favicon_urls_.clear();
-
- // Wait till the user navigates to a new URL to start checking the cache
- // again. The cache may be ignored for non-reload navigations (e.g.
- // history.replace() in-page navigation). This is allowed to increase the
- // likelihood that "reloading a page ignoring the cache" redownloads the
- // favicon. In particular, a page may do an in-page navigation before
- // FaviconHandler has the time to determine that the favicon needs to be
- // redownloaded.
- GURL url = details.entry->GetURL();
- if (url != bypass_cache_page_url_)
- bypass_cache_page_url_ = GURL();
-
- // Get the favicon, either from history or request it from the net.
- FetchFavicon(url);
-}
-
-void FaviconTabHelper::DidUpdateFaviconURL(
- const std::vector<content::FaviconURL>& candidates) {
- DCHECK(!candidates.empty());
- favicon_urls_ = candidates;
- std::vector<favicon::FaviconURL> favicon_urls =
- favicon::FaviconURLsFromContentFaviconURLs(candidates);
- favicon_handler_->OnUpdateFaviconURL(favicon_urls);
- if (touch_icon_handler_.get())
- touch_icon_handler_->OnUpdateFaviconURL(favicon_urls);
- if (large_icon_handler_.get())
- large_icon_handler_->OnUpdateFaviconURL(favicon_urls);
+FaviconTabHelper::FaviconTabHelper(content::WebContents* web_contents,
+ favicon::FaviconService* favicon_service,
+ history::HistoryService* history_service,
+ bookmarks::BookmarkModel* bookmark_model)
+ : favicon::ContentFaviconDriver(web_contents,
+ favicon_service,
+ history_service,
+ bookmark_model) {
}
diff --git a/chrome/browser/favicon/favicon_tab_helper.h b/chrome/browser/favicon/favicon_tab_helper.h
index 537ee40..e907090 100644
--- a/chrome/browser/favicon/favicon_tab_helper.h
+++ b/chrome/browser/favicon/favicon_tab_helper.h
@@ -5,115 +5,23 @@
#ifndef CHROME_BROWSER_FAVICON_FAVICON_TAB_HELPER_H_
#define CHROME_BROWSER_FAVICON_FAVICON_TAB_HELPER_H_
-#include <vector>
+#include "base/macros.h"
+#include "components/favicon/content/content_favicon_driver.h"
-#include "base/basictypes.h"
-#include "base/callback.h"
-#include "base/observer_list.h"
-#include "components/favicon/core/favicon_driver.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
-#include "content/public/common/favicon_url.h"
-
-class GURL;
-class SkBitmap;
-
-namespace gfx {
-class Image;
-}
-
-namespace bookmarks {
-class BookmarkModel;
-}
-
-namespace content {
-struct FaviconStatus;
-}
-
-namespace favicon {
-class FaviconDriverObserver;
-class FaviconHandler;
-class FaviconService;
-}
-
-namespace history {
-class HistoryService;
-}
-
-// FaviconTabHelper works with favicon::FaviconHandlers to fetch the favicons.
-//
-// FetchFavicon fetches the given page's icons. It requests the icons from the
-// history backend. If the icon is not available or expired, the icon will be
-// downloaded and saved in the history backend.
-//
-class FaviconTabHelper : public content::WebContentsObserver,
- public favicon::FaviconDriver,
- public content::WebContentsUserData<FaviconTabHelper> {
+// FaviconTabHelper provides helper factory for ContentFaviconDriver.
+class FaviconTabHelper : public favicon::ContentFaviconDriver {
public:
- ~FaviconTabHelper() override;
-
static void CreateForWebContents(content::WebContents* web_contents);
- // Initiates loading the favicon for the specified url.
- void FetchFavicon(const GURL& url);
-
- // Returns the favicon for this tab, or IDR_DEFAULT_FAVICON if the tab does
- // not have a favicon. The default implementation uses the current navigation
- // entry. This will return an empty bitmap if there are no navigation
- // entries, which should rarely happen.
- gfx::Image GetFavicon() const;
-
- // Returns true if we have the favicon for the page.
- bool FaviconIsValid() const;
+ // TODO(sdefresne): remove this method once all clients have been ported to
+ // use ContentFaviconDriver::FromWebContents() instead.
+ static FaviconTabHelper* FromWebContents(content::WebContents* web_contents);
// Returns whether the favicon should be displayed. If this returns false, no
// space is provided for the favicon, and the favicon is never displayed.
- bool ShouldDisplayFavicon();
-
- // Returns the current tab's favicon urls. If this is empty,
- // DidUpdateFaviconURL has not yet been called for the current navigation.
- const std::vector<content::FaviconURL>& favicon_urls() const {
- return favicon_urls_;
- }
-
- // content::WebContentsObserver override. Must be public, because also
- // called from PrerenderContents.
- void DidUpdateFaviconURL(
- const std::vector<content::FaviconURL>& candidates) override;
-
- // Saves the favicon for the current page.
- void SaveFavicon();
-
- void AddObserver(favicon::FaviconDriverObserver* observer);
- void RemoveObserver(favicon::FaviconDriverObserver* observer);
-
- // favicon::FaviconDriver methods.
- int StartDownload(const GURL& url, int max_bitmap_size) override;
- bool IsOffTheRecord() override;
- bool IsBookmarked(const GURL& url) override;
- GURL GetActiveURL() override;
- base::string16 GetActiveTitle() override;
- bool GetActiveFaviconValidity() override;
- void SetActiveFaviconValidity(bool valid) override;
- GURL GetActiveFaviconURL() override;
- void SetActiveFaviconURL(const GURL& url) override;
- gfx::Image GetActiveFaviconImage() override;
- void SetActiveFaviconImage(const gfx::Image& image) override;
- void OnFaviconAvailable(const gfx::Image& image,
- const GURL& url,
- bool is_active_favicon) override;
- void NotifyFaviconUpdated(bool icon_url_changed) override;
-
- // Favicon download callback.
- void DidDownloadFavicon(
- int id,
- int http_status_code,
- const GURL& image_url,
- const std::vector<SkBitmap>& bitmaps,
- const std::vector<gfx::Size>& original_bitmap_sizes);
+ static bool ShouldDisplayFavicon(content::WebContents* web_contents);
private:
- friend class content::WebContentsUserData<FaviconTabHelper>;
friend class FaviconTabHelperTest;
// Creates a new FaviconTabHelper bound to |web_contents|. Initialize
@@ -124,37 +32,6 @@ class FaviconTabHelper : public content::WebContentsObserver,
history::HistoryService* history_service,
bookmarks::BookmarkModel* bookmark_model);
- // content::WebContentsObserver overrides.
- void DidStartNavigationToPendingEntry(
- const GURL& url,
- content::NavigationController::ReloadType reload_type) override;
- void DidNavigateMainFrame(
- const content::LoadCommittedDetails& details,
- const content::FrameNavigateParams& params) override;
-
- // Helper method that returns the active navigation entry's favicon.
- content::FaviconStatus& GetFaviconStatus();
-
- // KeyedService used by FaviconTabHelper. They may be null during testing, but
- // if they are defined, they must outlive the FaviconTabHelper.
- favicon::FaviconService* favicon_service_;
- history::HistoryService* history_service_;
- bookmarks::BookmarkModel* bookmark_model_;
-
- std::vector<content::FaviconURL> favicon_urls_;
-
- // Bypass cache when downloading favicons for this page URL.
- GURL bypass_cache_page_url_;
-
- // FaviconHandlers used to download the different kind of favicons. Both
- // |touch_icon_handler_| and |large_icon_handler_| may be null depending
- // on the platform or variations.
- scoped_ptr<favicon::FaviconHandler> favicon_handler_;
- scoped_ptr<favicon::FaviconHandler> touch_icon_handler_;
- scoped_ptr<favicon::FaviconHandler> large_icon_handler_;
-
- ObserverList<favicon::FaviconDriverObserver> observer_list_;
-
DISALLOW_COPY_AND_ASSIGN(FaviconTabHelper);
};
diff --git a/chrome/browser/favicon/favicon_tab_helper_browsertest.cc b/chrome/browser/favicon/favicon_tab_helper_browsertest.cc
index 8722b5b..567d825 100644
--- a/chrome/browser/favicon/favicon_tab_helper_browsertest.cc
+++ b/chrome/browser/favicon/favicon_tab_helper_browsertest.cc
@@ -187,11 +187,8 @@ class FaviconTabHelperTest : public InProcessBrowserTest,
// FaviconTabHelperPendingTaskChecker:
bool HasPendingTasks() override {
- favicon::FaviconHandler* favicon_handler =
- FaviconTabHelper::FromWebContents(web_contents())
- ->favicon_handler_.get();
- return !favicon_handler->download_requests_.empty() ||
- favicon_handler->cancelable_task_tracker_.HasTrackedTasks();
+ return FaviconTabHelper::FromWebContents(web_contents())
+ ->HasPendingTasksForTest();
}
private:
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
index c13b362..8dde6a25 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
@@ -1554,10 +1554,8 @@ NSImage* Overlay(NSImage* ground, NSImage* overlay, CGFloat alpha) {
NSInteger index = [self indexFromModelIndex:modelIndex];
TabController* tabController = [tabArray_ objectAtIndex:index];
- FaviconTabHelper* favicon_tab_helper =
- FaviconTabHelper::FromWebContents(contents);
bool oldHasIcon = [tabController iconView] != nil;
- bool newHasIcon = favicon_tab_helper->ShouldDisplayFavicon() ||
+ bool newHasIcon = FaviconTabHelper::ShouldDisplayFavicon(contents) ||
tabStripModel_->IsMiniTab(modelIndex); // Always show icon if mini.
TabLoadingState oldState = [tabController loadingState];
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index ee646d4..23a17e9 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -509,7 +509,8 @@ void BrowserTabStripController::SetTabRendererDataFromModel(
data->crashed_status = contents->GetCrashedStatus();
data->incognito = contents->GetBrowserContext()->IsOffTheRecord();
data->mini = model_->IsMiniTab(model_index);
- data->show_icon = data->mini || favicon_tab_helper->ShouldDisplayFavicon();
+ data->show_icon =
+ data->mini || FaviconTabHelper::ShouldDisplayFavicon(contents);
data->blocked = model_->IsTabBlocked(model_index);
data->app = extensions::TabHelper::FromWebContents(contents)->is_app();
data->media_state = chrome::GetTabMediaStateForContents(contents);
diff --git a/components/favicon.gypi b/components/favicon.gypi
index f2c9cf5..d150316 100644
--- a/components/favicon.gypi
+++ b/components/favicon.gypi
@@ -9,7 +9,9 @@
'target_name': 'favicon_core',
'type': 'static_library',
'dependencies': [
+ '../base/base.gyp:base',
'../skia/skia.gyp:skia',
+ '../ui/base/ui_base.gyp:ui_base',
'../ui/gfx/gfx.gyp:gfx',
'../url/url.gyp:url_lib',
'bookmarks_browser',
@@ -23,7 +25,10 @@
'favicon/core/fallback_icon_service.cc',
'favicon/core/fallback_icon_service.h',
'favicon/core/favicon_client.h',
+ 'favicon/core/favicon_driver.cc',
'favicon/core/favicon_driver.h',
+ 'favicon/core/favicon_driver_impl.cc',
+ 'favicon/core/favicon_driver_impl.h',
'favicon/core/favicon_driver_observer.h',
'favicon/core/favicon_handler.cc',
'favicon/core/favicon_handler.h',
@@ -45,13 +50,17 @@
'target_name': 'favicon_content',
'type': 'static_library',
'dependencies': [
+ '../base/base.gyp:base',
'../content/content.gyp:content_browser',
'../content/content.gyp:content_common',
+ '../ui/gfx/gfx.gyp:gfx',
'favicon_base',
'favicon_core',
],
'sources': [
# Note: sources list duplicated in GN build.
+ 'favicon/content/content_favicon_driver.cc',
+ 'favicon/content/content_favicon_driver.h',
'favicon/content/favicon_url_util.cc',
'favicon/content/favicon_url_util.h',
],
@@ -67,13 +76,17 @@
'target_name': 'favicon_ios',
'type': 'static_library',
'dependencies': [
+ '../base/base.gyp:base',
'../ios/web/ios_web.gyp:ios_web',
+ '../ui/gfx/gfx.gyp:gfx',
'favicon_base',
'favicon_core',
],
'sources': [
- 'favicon/ios/favicon_url_util.h',
'favicon/ios/favicon_url_util.cc',
+ 'favicon/ios/favicon_url_util.h',
+ 'favicon/ios/web_favicon_driver.cc',
+ 'favicon/ios/web_favicon_driver.h',
],
'include_dirs': [
'..',
diff --git a/components/favicon/DEPS b/components/favicon/DEPS
index b6ea2b3..9c23536 100644
--- a/components/favicon/DEPS
+++ b/components/favicon/DEPS
@@ -1,4 +1,5 @@
include_rules = [
"+components/favicon_base",
+ "+ui/base",
"+ui/gfx",
]
diff --git a/components/favicon/content/BUILD.gn b/components/favicon/content/BUILD.gn
index 68501ea..1bea91e 100644
--- a/components/favicon/content/BUILD.gn
+++ b/components/favicon/content/BUILD.gn
@@ -4,14 +4,18 @@
static_library("content") {
sources = [
+ "content_favicon_driver.cc",
+ "content_favicon_driver.h",
"favicon_url_util.cc",
"favicon_url_util.h",
]
deps = [
+ "//base",
"//components/favicon/core",
"//components/favicon_base",
"//content/public/browser",
"//content/public/common",
+ "//ui/gfx",
]
}
diff --git a/components/favicon/content/content_favicon_driver.cc b/components/favicon/content/content_favicon_driver.cc
new file mode 100644
index 0000000..c8efaad
--- /dev/null
+++ b/components/favicon/content/content_favicon_driver.cc
@@ -0,0 +1,182 @@
+// Copyright 2015 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 "components/favicon/content/content_favicon_driver.h"
+
+#include "base/bind.h"
+#include "components/favicon/content/favicon_url_util.h"
+#include "components/favicon/core/favicon_url.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/favicon_status.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_details.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/common/favicon_url.h"
+#include "ui/gfx/image/image.h"
+
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(favicon::ContentFaviconDriver);
+
+namespace favicon {
+
+// static
+void ContentFaviconDriver::CreateForWebContents(
+ content::WebContents* web_contents,
+ FaviconService* favicon_service,
+ history::HistoryService* history_service,
+ bookmarks::BookmarkModel* bookmark_model) {
+ if (FromWebContents(web_contents))
+ return;
+
+ web_contents->SetUserData(
+ UserDataKey(), new ContentFaviconDriver(web_contents, favicon_service,
+ history_service, bookmark_model));
+}
+
+gfx::Image ContentFaviconDriver::GetFavicon() const {
+ // Like GetTitle(), we also want to use the favicon for the last committed
+ // entry rather than a pending navigation entry.
+ const content::NavigationController& controller =
+ web_contents()->GetController();
+ content::NavigationEntry* entry = controller.GetTransientEntry();
+ if (entry)
+ return entry->GetFavicon().image;
+
+ entry = controller.GetLastCommittedEntry();
+ if (entry)
+ return entry->GetFavicon().image;
+ return gfx::Image();
+}
+
+bool ContentFaviconDriver::FaviconIsValid() const {
+ const content::NavigationController& controller =
+ web_contents()->GetController();
+ content::NavigationEntry* entry = controller.GetTransientEntry();
+ if (entry)
+ return entry->GetFavicon().valid;
+
+ entry = controller.GetLastCommittedEntry();
+ if (entry)
+ return entry->GetFavicon().valid;
+
+ return false;
+}
+
+int ContentFaviconDriver::StartDownload(const GURL& url, int max_image_size) {
+ if (WasUnableToDownloadFavicon(url)) {
+ DVLOG(1) << "Skip Failed FavIcon: " << url;
+ return 0;
+ }
+
+ bool bypass_cache = (bypass_cache_page_url_ == GetActiveURL());
+ bypass_cache_page_url_ = GURL();
+
+ return web_contents()->DownloadImage(
+ url, true, max_image_size, bypass_cache,
+ base::Bind(&FaviconDriverImpl::DidDownloadFavicon,
+ base::Unretained(this)));
+}
+
+bool ContentFaviconDriver::IsOffTheRecord() {
+ DCHECK(web_contents());
+ return web_contents()->GetBrowserContext()->IsOffTheRecord();
+}
+
+GURL ContentFaviconDriver::GetActiveURL() {
+ content::NavigationEntry* entry =
+ web_contents()->GetController().GetActiveEntry();
+ return entry ? entry->GetURL() : GURL();
+}
+
+base::string16 ContentFaviconDriver::GetActiveTitle() {
+ content::NavigationEntry* entry =
+ web_contents()->GetController().GetActiveEntry();
+ return entry ? entry->GetTitle() : base::string16();
+}
+
+bool ContentFaviconDriver::GetActiveFaviconValidity() {
+ return GetFaviconStatus().valid;
+}
+
+void ContentFaviconDriver::SetActiveFaviconValidity(bool valid) {
+ GetFaviconStatus().valid = valid;
+}
+
+GURL ContentFaviconDriver::GetActiveFaviconURL() {
+ return GetFaviconStatus().url;
+}
+
+void ContentFaviconDriver::SetActiveFaviconURL(const GURL& url) {
+ GetFaviconStatus().url = url;
+}
+
+gfx::Image ContentFaviconDriver::GetActiveFaviconImage() {
+ return GetFaviconStatus().image;
+}
+
+void ContentFaviconDriver::SetActiveFaviconImage(const gfx::Image& image) {
+ GetFaviconStatus().image = image;
+}
+
+content::FaviconStatus& ContentFaviconDriver::GetFaviconStatus() {
+ DCHECK(web_contents()->GetController().GetActiveEntry());
+ return web_contents()->GetController().GetActiveEntry()->GetFavicon();
+}
+
+ContentFaviconDriver::ContentFaviconDriver(
+ content::WebContents* web_contents,
+ FaviconService* favicon_service,
+ history::HistoryService* history_service,
+ bookmarks::BookmarkModel* bookmark_model)
+ : content::WebContentsObserver(web_contents),
+ FaviconDriverImpl(favicon_service, history_service, bookmark_model) {
+}
+
+ContentFaviconDriver::~ContentFaviconDriver() {
+}
+
+void ContentFaviconDriver::NotifyFaviconUpdated(bool icon_url_changed) {
+ FaviconDriverImpl::NotifyFaviconUpdated(icon_url_changed);
+ web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
+}
+
+void ContentFaviconDriver::DidUpdateFaviconURL(
+ const std::vector<content::FaviconURL>& candidates) {
+ DCHECK(!candidates.empty());
+ favicon_urls_ = candidates;
+ OnUpdateFaviconURL(FaviconURLsFromContentFaviconURLs(candidates));
+}
+
+void ContentFaviconDriver::DidStartNavigationToPendingEntry(
+ const GURL& url,
+ content::NavigationController::ReloadType reload_type) {
+ if (reload_type == content::NavigationController::NO_RELOAD ||
+ IsOffTheRecord())
+ return;
+
+ bypass_cache_page_url_ = url;
+ SetFaviconOutOfDateForPage(
+ url, reload_type == content::NavigationController::RELOAD_IGNORING_CACHE);
+}
+
+void ContentFaviconDriver::DidNavigateMainFrame(
+ const content::LoadCommittedDetails& details,
+ const content::FrameNavigateParams& params) {
+ favicon_urls_.clear();
+
+ // Wait till the user navigates to a new URL to start checking the cache
+ // again. The cache may be ignored for non-reload navigations (e.g.
+ // history.replace() in-page navigation). This is allowed to increase the
+ // likelihood that "reloading a page ignoring the cache" redownloads the
+ // favicon. In particular, a page may do an in-page navigation before
+ // FaviconHandler has the time to determine that the favicon needs to be
+ // redownloaded.
+ GURL url = details.entry->GetURL();
+ if (url != bypass_cache_page_url_)
+ bypass_cache_page_url_ = GURL();
+
+ // Get the favicon, either from history or request it from the net.
+ FetchFavicon(url);
+}
+
+} // namespace favicon
diff --git a/components/favicon/content/content_favicon_driver.h b/components/favicon/content/content_favicon_driver.h
new file mode 100644
index 0000000..18ef1bf
--- /dev/null
+++ b/components/favicon/content/content_favicon_driver.h
@@ -0,0 +1,88 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_FAVICON_CONTENT_CONTENT_FAVICON_DRIVER_H_
+#define COMPONENTS_FAVICON_CONTENT_CONTENT_FAVICON_DRIVER_H_
+
+#include "components/favicon/core/favicon_driver_impl.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+#include "url/gurl.h"
+
+namespace content {
+struct FaviconStatus;
+struct FaviconURL;
+class WebContents;
+}
+
+namespace favicon {
+
+// ContentFaviconDriver is an implementation of FaviconDriver that listens to
+// WebContents events to start download of favicons and to get informed when the
+// favicon download has completed.
+class ContentFaviconDriver
+ : public content::WebContentsObserver,
+ public content::WebContentsUserData<ContentFaviconDriver>,
+ public FaviconDriverImpl {
+ public:
+ static void CreateForWebContents(content::WebContents* web_contents,
+ FaviconService* favicon_service,
+ history::HistoryService* history_service,
+ bookmarks::BookmarkModel* bookmark_model);
+
+ // Returns the current tab's favicon URLs. If this is empty,
+ // DidUpdateFaviconURL has not yet been called for the current navigation.
+ const std::vector<content::FaviconURL>& favicon_urls() const {
+ return favicon_urls_;
+ }
+
+ // FaviconDriver implementation.
+ gfx::Image GetFavicon() const override;
+ bool FaviconIsValid() const override;
+ int StartDownload(const GURL& url, int max_bitmap_size) override;
+ bool IsOffTheRecord() override;
+ GURL GetActiveURL() override;
+ base::string16 GetActiveTitle() override;
+ bool GetActiveFaviconValidity() override;
+ void SetActiveFaviconValidity(bool valid) override;
+ GURL GetActiveFaviconURL() override;
+ void SetActiveFaviconURL(const GURL& url) override;
+ gfx::Image GetActiveFaviconImage() override;
+ void SetActiveFaviconImage(const gfx::Image& image) override;
+
+ protected:
+ ContentFaviconDriver(content::WebContents* web_contents,
+ FaviconService* favicon_service,
+ history::HistoryService* history_service,
+ bookmarks::BookmarkModel* bookmark_model);
+ ~ContentFaviconDriver() override;
+
+ private:
+ friend class content::WebContentsUserData<ContentFaviconDriver>;
+
+ // FaviconDriver implementation.
+ void NotifyFaviconUpdated(bool icon_url_changed) override;
+
+ // content::WebContentsObserver implementation.
+ void DidUpdateFaviconURL(
+ const std::vector<content::FaviconURL>& candidates) override;
+ void DidStartNavigationToPendingEntry(
+ const GURL& url,
+ content::NavigationController::ReloadType reload_type) override;
+ void DidNavigateMainFrame(
+ const content::LoadCommittedDetails& details,
+ const content::FrameNavigateParams& params) override;
+
+ // Returns the active navigation entry's favicon.
+ content::FaviconStatus& GetFaviconStatus();
+
+ GURL bypass_cache_page_url_;
+ std::vector<content::FaviconURL> favicon_urls_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentFaviconDriver);
+};
+
+} // namespace favicon
+
+#endif // COMPONENTS_FAVICON_CONTENT_CONTENT_FAVICON_DRIVER_H_
diff --git a/components/favicon/core/BUILD.gn b/components/favicon/core/BUILD.gn
index 4ac4750..7f9b762 100644
--- a/components/favicon/core/BUILD.gn
+++ b/components/favicon/core/BUILD.gn
@@ -8,7 +8,10 @@ static_library("core") {
"fallback_icon_service.cc",
"fallback_icon_service.h",
"favicon_client.h",
+ "favicon_driver.cc",
"favicon_driver.h",
+ "favicon_driver_impl.cc",
+ "favicon_driver_impl.h",
"favicon_driver_observer.h",
"favicon_handler.cc",
"favicon_handler.h",
@@ -19,11 +22,13 @@ static_library("core") {
]
deps = [
+ "//base",
"//components/bookmarks/browser",
"//components/favicon_base",
"//components/history/core/browser",
"//components/keyed_service/core",
"//skia",
+ "//ui/base",
"//ui/gfx",
"//url",
]
diff --git a/components/favicon/core/favicon_driver.cc b/components/favicon/core/favicon_driver.cc
new file mode 100644
index 0000000..0063229
--- /dev/null
+++ b/components/favicon/core/favicon_driver.cc
@@ -0,0 +1,35 @@
+// Copyright 2015 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 "components/favicon/core/favicon_driver.h"
+
+#include "components/favicon/core/favicon_driver_observer.h"
+
+namespace favicon {
+
+void FaviconDriver::AddObserver(FaviconDriverObserver* observer) {
+ observer_list_.AddObserver(observer);
+}
+
+void FaviconDriver::RemoveObserver(FaviconDriverObserver* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
+FaviconDriver::FaviconDriver() {
+}
+
+FaviconDriver::~FaviconDriver() {
+}
+
+void FaviconDriver::NotifyFaviconAvailable(const gfx::Image& image) {
+ FOR_EACH_OBSERVER(FaviconDriverObserver, observer_list_,
+ OnFaviconAvailable(image));
+}
+
+void FaviconDriver::NotifyFaviconUpdated(bool icon_url_changed) {
+ FOR_EACH_OBSERVER(FaviconDriverObserver, observer_list_,
+ OnFaviconUpdated(this, icon_url_changed));
+}
+
+} // namespace favicon
diff --git a/components/favicon/core/favicon_driver.h b/components/favicon/core/favicon_driver.h
index 4347ecb..a030845a 100644
--- a/components/favicon/core/favicon_driver.h
+++ b/components/favicon/core/favicon_driver.h
@@ -6,6 +6,7 @@
#define COMPONENTS_FAVICON_CORE_FAVICON_DRIVER_H_
#include "base/macros.h"
+#include "base/observer_list.h"
#include "base/strings/string16.h"
class GURL;
@@ -16,11 +17,33 @@ class Image;
namespace favicon {
-// Interface that allows Favicon core code to interact with its driver (i.e.,
-// obtain information from it and give information to it). A concrete
-// implementation must be provided by the driver.
+class FaviconDriverObserver;
+
+// Interface that allows favicon core code to obtain information about the
+// current page. This is partially implemented by FaviconDriverImpl, and
+// concrete implementation should be based on that class instead of directly
+// subclassing FaviconDriver.
class FaviconDriver {
public:
+ // Adds/Removes an observer.
+ void AddObserver(FaviconDriverObserver* observer);
+ void RemoveObserver(FaviconDriverObserver* observer);
+
+ // Initiates loading the favicon for the specified url.
+ virtual void FetchFavicon(const GURL& url) = 0;
+
+ // Saves the favicon for the current page.
+ virtual void SaveFavicon() = 0;
+
+ // Returns the favicon for this tab, or IDR_DEFAULT_FAVICON if the tab does
+ // not have a favicon. The default implementation uses the current navigation
+ // entry. Returns an empty bitmap if there are no navigation entries, which
+ // should rarely happen.
+ virtual gfx::Image GetFavicon() const = 0;
+
+ // Returns true if we have the favicon for the page.
+ virtual bool FaviconIsValid() const = 0;
+
// Starts the download for the given favicon. When finished, the driver
// will call OnDidDownloadFavicon() with the results.
// Returns the unique id of the download request. The id will be passed
@@ -74,16 +97,26 @@ class FaviconDriver {
const GURL& icon_url,
bool is_active_favicon) = 0;
- // Sends notification that the current page favicon has changed.
- // |icon_url_changed| is true if the URL of the favicon changed in addition to
- // the favicon image.
- virtual void NotifyFaviconUpdated(bool icon_url_changed) = 0;
+ // Returns whether the driver is waiting for a download to complete or for
+ // data from the FaviconService. Reserved for testing.
+ virtual bool HasPendingTasksForTest() = 0;
protected:
- FaviconDriver() {}
- virtual ~FaviconDriver() {}
+ FaviconDriver();
+ virtual ~FaviconDriver();
+
+ // Informs FaviconDriverObservers that favicon |image| has been retrieved from
+ // either website or cached storage.
+ void NotifyFaviconAvailable(const gfx::Image& image);
+
+ // Informs FaviconDriverObservers that favicon has changed for the current
+ // page. |icon_url_changed| is true if the favicon URL has also changed since
+ // the last call.
+ virtual void NotifyFaviconUpdated(bool icon_url_changed);
private:
+ ObserverList<FaviconDriverObserver> observer_list_;
+
DISALLOW_COPY_AND_ASSIGN(FaviconDriver);
};
diff --git a/components/favicon/core/favicon_driver_impl.cc b/components/favicon/core/favicon_driver_impl.cc
new file mode 100644
index 0000000..c95bf3a
--- /dev/null
+++ b/components/favicon/core/favicon_driver_impl.cc
@@ -0,0 +1,178 @@
+// Copyright 2015 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 "components/favicon/core/favicon_driver_impl.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/metrics/field_trial.h"
+#include "base/strings/string_util.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/favicon/core/favicon_driver_observer.h"
+#include "components/favicon/core/favicon_handler.h"
+#include "components/favicon/core/favicon_service.h"
+#include "components/history/core/browser/history_service.h"
+#include "ui/base/ui_base_switches.h"
+
+namespace favicon {
+namespace {
+
+// Returns whether icon NTP is enabled by experiment.
+// TODO(huangs): Remove all 3 copies of this routine once Icon NTP launches.
+bool IsIconNTPEnabled() {
+ // Note: It's important to query the field trial state first, to ensure that
+ // UMA reports the correct group.
+ const std::string group_name = base::FieldTrialList::FindFullName("IconNTP");
+ using base::CommandLine;
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableIconNtp))
+ return false;
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableIconNtp))
+ return true;
+
+ return StartsWithASCII(group_name, "Enabled", true);
+}
+
+#if defined(OS_ANDROID) || defined(OS_IOS)
+const bool kEnableTouchIcon = true;
+#else
+const bool kEnableTouchIcon = false;
+#endif
+
+} // namespace
+
+FaviconDriverImpl::FaviconDriverImpl(FaviconService* favicon_service,
+ history::HistoryService* history_service,
+ bookmarks::BookmarkModel* bookmark_model)
+ : favicon_service_(favicon_service),
+ history_service_(history_service),
+ bookmark_model_(bookmark_model) {
+ favicon_handler_.reset(new FaviconHandler(
+ favicon_service_, this, FaviconHandler::FAVICON, kEnableTouchIcon));
+ if (kEnableTouchIcon) {
+ touch_icon_handler_.reset(new FaviconHandler(favicon_service_, this,
+ FaviconHandler::TOUCH, true));
+ }
+ if (IsIconNTPEnabled()) {
+ large_icon_handler_.reset(new FaviconHandler(favicon_service_, this,
+ FaviconHandler::LARGE, true));
+ }
+}
+
+FaviconDriverImpl::~FaviconDriverImpl() {
+}
+
+void FaviconDriverImpl::FetchFavicon(const GURL& url) {
+ favicon_handler_->FetchFavicon(url);
+ if (touch_icon_handler_.get())
+ touch_icon_handler_->FetchFavicon(url);
+ if (large_icon_handler_.get())
+ large_icon_handler_->FetchFavicon(url);
+}
+
+void FaviconDriverImpl::SaveFavicon() {
+ GURL active_url = GetActiveURL();
+ if (active_url.is_empty())
+ return;
+
+ // Make sure the page is in history, otherwise adding the favicon does
+ // nothing.
+ if (!history_service_)
+ return;
+ history_service_->AddPageNoVisitForBookmark(active_url, GetActiveTitle());
+
+ if (!favicon_service_)
+ return;
+ if (!GetActiveFaviconValidity())
+ return;
+ GURL favicon_url = GetActiveFaviconURL();
+ if (favicon_url.is_empty())
+ return;
+ gfx::Image image = GetActiveFaviconImage();
+ if (image.IsEmpty())
+ return;
+ favicon_service_->SetFavicons(active_url, favicon_url, favicon_base::FAVICON,
+ image);
+}
+
+void FaviconDriverImpl::DidDownloadFavicon(
+ int id,
+ int http_status_code,
+ const GURL& image_url,
+ const std::vector<SkBitmap>& bitmaps,
+ const std::vector<gfx::Size>& original_bitmap_sizes) {
+ if (bitmaps.empty() && http_status_code == 404) {
+ DVLOG(1) << "Failed to Download Favicon:" << image_url;
+ if (favicon_service_)
+ favicon_service_->UnableToDownloadFavicon(image_url);
+ }
+
+ favicon_handler_->OnDidDownloadFavicon(id, image_url, bitmaps,
+ original_bitmap_sizes);
+ if (touch_icon_handler_.get()) {
+ touch_icon_handler_->OnDidDownloadFavicon(id, image_url, bitmaps,
+ original_bitmap_sizes);
+ }
+ if (large_icon_handler_.get()) {
+ large_icon_handler_->OnDidDownloadFavicon(id, image_url, bitmaps,
+ original_bitmap_sizes);
+ }
+}
+
+bool FaviconDriverImpl::IsBookmarked(const GURL& url) {
+ return bookmark_model_ && bookmark_model_->IsBookmarked(url);
+}
+
+void FaviconDriverImpl::OnFaviconAvailable(const gfx::Image& image,
+ const GURL& icon_url,
+ bool is_active_favicon) {
+ if (is_active_favicon) {
+ bool icon_url_changed = GetActiveFaviconURL() != icon_url;
+ // No matter what happens, we need to mark the favicon as being set.
+ SetActiveFaviconValidity(true);
+ SetActiveFaviconURL(icon_url);
+
+ if (image.IsEmpty())
+ return;
+
+ SetActiveFaviconImage(image);
+ NotifyFaviconUpdated(icon_url_changed);
+ }
+ if (!image.IsEmpty())
+ NotifyFaviconAvailable(image);
+}
+
+bool FaviconDriverImpl::HasPendingTasksForTest() {
+ if (favicon_handler_->HasPendingTasksForTest())
+ return true;
+ if (touch_icon_handler_ && touch_icon_handler_->HasPendingTasksForTest())
+ return true;
+ if (large_icon_handler_ && large_icon_handler_->HasPendingTasksForTest())
+ return true;
+ return false;
+}
+
+bool FaviconDriverImpl::WasUnableToDownloadFavicon(const GURL& url) {
+ return favicon_service_ && favicon_service_->WasUnableToDownloadFavicon(url);
+}
+
+void FaviconDriverImpl::SetFaviconOutOfDateForPage(const GURL& url,
+ bool force_reload) {
+ if (favicon_service_) {
+ favicon_service_->SetFaviconOutOfDateForPage(url);
+ if (force_reload)
+ favicon_service_->ClearUnableToDownloadFavicons();
+ }
+}
+
+void FaviconDriverImpl::OnUpdateFaviconURL(
+ const std::vector<FaviconURL>& candidates) {
+ DCHECK(!candidates.empty());
+ favicon_handler_->OnUpdateFaviconURL(candidates);
+ if (touch_icon_handler_.get())
+ touch_icon_handler_->OnUpdateFaviconURL(candidates);
+ if (large_icon_handler_.get())
+ large_icon_handler_->OnUpdateFaviconURL(candidates);
+}
+
+} // namespace favicon
diff --git a/components/favicon/core/favicon_driver_impl.h b/components/favicon/core/favicon_driver_impl.h
new file mode 100644
index 0000000..f4a93d6
--- /dev/null
+++ b/components/favicon/core/favicon_driver_impl.h
@@ -0,0 +1,98 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_FAVICON_CORE_FAVICON_DRIVER_IMPL_H_
+#define COMPONENTS_FAVICON_CORE_FAVICON_DRIVER_IMPL_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "components/favicon/core/favicon_driver.h"
+
+class GURL;
+class SkBitmap;
+
+namespace bookmarks {
+class BookmarkModel;
+}
+
+namespace gfx {
+class Image;
+class Size;
+}
+
+namespace history {
+class HistoryService;
+}
+
+namespace favicon {
+
+class FaviconDriverObserver;
+class FaviconHandler;
+class FaviconService;
+struct FaviconURL;
+
+// FaviconDriverImpl is a partial implementation of FaviconDriver that allow
+// sharing implementation between different embedder.
+//
+// FaviconDriverImpl works with FaviconHandlers to fetch the favicons. It
+// fetches the given page's icons, requesting them from history backend. If the
+// icon is not available or expired, the icon will be downloaded and saved in
+// the history backend.
+class FaviconDriverImpl : public FaviconDriver {
+ public:
+ // Favicon download callback.
+ // Public for testing.
+ void DidDownloadFavicon(int id,
+ int http_status_code,
+ const GURL& image_url,
+ const std::vector<SkBitmap>& bitmaps,
+ const std::vector<gfx::Size>& original_bitmap_sizes);
+
+ // FaviconDriver implementation.
+ void FetchFavicon(const GURL& url) override;
+ void SaveFavicon() override;
+ bool IsBookmarked(const GURL& url) override;
+ void OnFaviconAvailable(const gfx::Image& image,
+ const GURL& icon_url,
+ bool is_active_favicon) override;
+ bool HasPendingTasksForTest() override;
+
+ protected:
+ FaviconDriverImpl(FaviconService* favicon_service,
+ history::HistoryService* history_service,
+ bookmarks::BookmarkModel* bookmark_model);
+ ~FaviconDriverImpl() override;
+
+ // Returns whether downloading favicon for |url| previously failed.
+ bool WasUnableToDownloadFavicon(const GURL& url);
+
+ // Informs FaviconService that the favicon for |url| is out of date. If
+ // |force_reload| is true, then discard information about favicon download
+ // failures.
+ void SetFaviconOutOfDateForPage(const GURL& url, bool force_reload);
+
+ // Broadcasts new favicon URL candidates to FaviconHandlers.
+ void OnUpdateFaviconURL(const std::vector<FaviconURL>& candidates);
+
+ private:
+ // KeyedServices used by FaviconDriverImpl. They may be null during testing,
+ // but if they are defined, they must outlive the FaviconDriverImpl.
+ FaviconService* favicon_service_;
+ history::HistoryService* history_service_;
+ bookmarks::BookmarkModel* bookmark_model_;
+
+ // FaviconHandlers used to download the different kind of favicons. Both
+ // |touch_icon_handler_| and |large_icon_handler_| may be null depending
+ // on the platform or variations.
+ scoped_ptr<FaviconHandler> favicon_handler_;
+ scoped_ptr<FaviconHandler> touch_icon_handler_;
+ scoped_ptr<FaviconHandler> large_icon_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(FaviconDriverImpl);
+};
+
+} // namespace favicon
+
+#endif // COMPONENTS_FAVICON_CORE_FAVICON_DRIVER_IMPL_H_
diff --git a/components/favicon/core/favicon_handler.cc b/components/favicon/core/favicon_handler.cc
index adc0a5c..aff1626 100644
--- a/components/favicon/core/favicon_handler.cc
+++ b/components/favicon/core/favicon_handler.cc
@@ -450,6 +450,11 @@ void FaviconHandler::OnDidDownloadFavicon(
}
}
+bool FaviconHandler::HasPendingTasksForTest() {
+ return !download_requests_.empty() ||
+ cancelable_task_tracker_.HasTrackedTasks();
+}
+
bool FaviconHandler::PageChangedSinceFaviconWasRequested() {
if (UrlMatches(driver_->GetActiveURL(), url_) && url_.is_valid()) {
return false;
diff --git a/components/favicon/core/favicon_handler.h b/components/favicon/core/favicon_handler.h
index 960eba5..d8fee10 100644
--- a/components/favicon/core/favicon_handler.h
+++ b/components/favicon/core/favicon_handler.h
@@ -19,7 +19,6 @@
#include "ui/gfx/image/image.h"
#include "url/gurl.h"
-class FaviconTabHelperTest;
class SkBitmap;
class TestFaviconHandler;
@@ -118,6 +117,10 @@ class FaviconHandler {
return image_urls_;
}
+ // Returns whether the handler is waiting for a download to complete or for
+ // data from the FaviconService. Reserved for testing.
+ bool HasPendingTasksForTest();
+
protected:
// These virtual methods make FaviconHandler testable and are overridden by
// TestFaviconHandler.
@@ -155,7 +158,6 @@ class FaviconHandler {
private:
// For testing:
- friend class ::FaviconTabHelperTest;
friend class ::TestFaviconHandler;
// Represents an in progress download of an image from the renderer.
diff --git a/components/favicon/ios/web_favicon_driver.cc b/components/favicon/ios/web_favicon_driver.cc
new file mode 100644
index 0000000..b4eaac7
--- /dev/null
+++ b/components/favicon/ios/web_favicon_driver.cc
@@ -0,0 +1,122 @@
+// Copyright 2015 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 "components/favicon/ios/web_favicon_driver.h"
+
+#include "base/bind.h"
+#include "components/favicon/core/favicon_url.h"
+#include "components/favicon/ios/favicon_url_util.h"
+#include "ios/web/public/browser_state.h"
+#include "ios/web/public/favicon_status.h"
+#include "ios/web/public/navigation_item.h"
+#include "ios/web/public/navigation_manager.h"
+#include "ios/web/public/web_state/web_state.h"
+#include "ui/gfx/image/image.h"
+
+DEFINE_WEB_STATE_USER_DATA_KEY(favicon::WebFaviconDriver);
+
+namespace favicon {
+
+// static
+void WebFaviconDriver::CreateForWebState(
+ web::WebState* web_state,
+ FaviconService* favicon_service,
+ history::HistoryService* history_service,
+ bookmarks::BookmarkModel* bookmark_model) {
+ if (FromWebState(web_state))
+ return;
+
+ web_state->SetUserData(UserDataKey(),
+ new WebFaviconDriver(web_state, favicon_service,
+ history_service, bookmark_model));
+}
+
+gfx::Image WebFaviconDriver::GetFavicon() const {
+ web::NavigationItem* item =
+ web_state()->GetNavigationManager()->GetLastCommittedItem();
+ return item ? item->GetFavicon().image : gfx::Image();
+}
+
+bool WebFaviconDriver::FaviconIsValid() const {
+ web::NavigationItem* item =
+ web_state()->GetNavigationManager()->GetLastCommittedItem();
+ return item ? item->GetFavicon().valid : false;
+}
+
+int WebFaviconDriver::StartDownload(const GURL& url, int max_image_size) {
+ if (WasUnableToDownloadFavicon(url)) {
+ DVLOG(1) << "Skip Failed FavIcon: " << url;
+ return 0;
+ }
+
+ return web_state()->DownloadImage(
+ url, true, max_image_size, false,
+ base::Bind(&FaviconDriverImpl::DidDownloadFavicon,
+ base::Unretained(this)));
+}
+
+bool WebFaviconDriver::IsOffTheRecord() {
+ DCHECK(web_state());
+ return web_state()->GetBrowserState()->IsOffTheRecord();
+}
+
+GURL WebFaviconDriver::GetActiveURL() {
+ web::NavigationItem* item =
+ web_state()->GetNavigationManager()->GetVisibleItem();
+ return item ? item->GetURL() : GURL();
+}
+
+base::string16 WebFaviconDriver::GetActiveTitle() {
+ web::NavigationItem* item =
+ web_state()->GetNavigationManager()->GetVisibleItem();
+ return item ? item->GetTitle() : base::string16();
+}
+
+bool WebFaviconDriver::GetActiveFaviconValidity() {
+ return GetFaviconStatus().valid;
+}
+
+void WebFaviconDriver::SetActiveFaviconValidity(bool validity) {
+ GetFaviconStatus().valid = validity;
+}
+
+GURL WebFaviconDriver::GetActiveFaviconURL() {
+ return GetFaviconStatus().url;
+}
+
+void WebFaviconDriver::SetActiveFaviconURL(const GURL& url) {
+ GetFaviconStatus().url = url;
+}
+
+gfx::Image WebFaviconDriver::GetActiveFaviconImage() {
+ return GetFaviconStatus().image;
+}
+
+void WebFaviconDriver::SetActiveFaviconImage(const gfx::Image& image) {
+ GetFaviconStatus().image = image;
+}
+
+web::FaviconStatus& WebFaviconDriver::GetFaviconStatus() {
+ DCHECK(web_state()->GetNavigationManager()->GetVisibleItem());
+ return web_state()->GetNavigationManager()->GetVisibleItem()->GetFavicon();
+}
+
+WebFaviconDriver::WebFaviconDriver(web::WebState* web_state,
+ FaviconService* favicon_service,
+ history::HistoryService* history_service,
+ bookmarks::BookmarkModel* bookmark_model)
+ : web::WebStateObserver(web_state),
+ FaviconDriverImpl(favicon_service, history_service, bookmark_model) {
+}
+
+WebFaviconDriver::~WebFaviconDriver() {
+}
+
+void WebFaviconDriver::FaviconURLUpdated(
+ const std::vector<web::FaviconURL>& candidates) {
+ DCHECK(!candidates.empty());
+ OnUpdateFaviconURL(FaviconURLsFromWebFaviconURLs(candidates));
+}
+
+} // namespace favicon
diff --git a/components/favicon/ios/web_favicon_driver.h b/components/favicon/ios/web_favicon_driver.h
new file mode 100644
index 0000000..343d2be
--- /dev/null
+++ b/components/favicon/ios/web_favicon_driver.h
@@ -0,0 +1,66 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_FAVICON_IOS_WEB_FAVICON_DRIVER_H_
+#define COMPONENTS_FAVICON_IOS_WEB_FAVICON_DRIVER_H_
+
+#include "components/favicon/core/favicon_driver_impl.h"
+#include "ios/web/public/web_state/web_state_observer.h"
+#include "ios/web/public/web_state/web_state_user_data.h"
+
+namespace web {
+struct FaviconStatus;
+class WebState;
+}
+
+namespace favicon {
+
+// WebFaviconDriver is an implementation of FaviconDriver that listen to
+// WebState events to start download of favicons and to get informed when the
+// favicon download has completed.
+class WebFaviconDriver : public web::WebStateObserver,
+ public web::WebStateUserData<WebFaviconDriver>,
+ public FaviconDriverImpl {
+ public:
+ static void CreateForWebState(web::WebState* web_state,
+ FaviconService* favicon_service,
+ history::HistoryService* history_service,
+ bookmarks::BookmarkModel* bookmark_model);
+
+ // FaviconDriver implementation.
+ gfx::Image GetFavicon() const override;
+ bool FaviconIsValid() const override;
+ int StartDownload(const GURL& url, int max_bitmap_size) override;
+ bool IsOffTheRecord() override;
+ GURL GetActiveURL() override;
+ base::string16 GetActiveTitle() override;
+ bool GetActiveFaviconValidity() override;
+ void SetActiveFaviconValidity(bool valid) override;
+ GURL GetActiveFaviconURL() override;
+ void SetActiveFaviconURL(const GURL& url) override;
+ gfx::Image GetActiveFaviconImage() override;
+ void SetActiveFaviconImage(const gfx::Image& image) override;
+
+ private:
+ friend class web::WebStateUserData<WebFaviconDriver>;
+
+ WebFaviconDriver(web::WebState* web_state,
+ FaviconService* favicon_service,
+ history::HistoryService* history_service,
+ bookmarks::BookmarkModel* bookmark_model);
+ ~WebFaviconDriver() override;
+
+ // web::WebStateObserver implementation.
+ void FaviconURLUpdated(
+ const std::vector<web::FaviconURL>& candidates) override;
+
+ // Returns the active navigation entry's favicon.
+ web::FaviconStatus& GetFaviconStatus();
+
+ DISALLOW_COPY_AND_ASSIGN(WebFaviconDriver);
+};
+
+} // namespace favicon
+
+#endif // COMPONENTS_FAVICON_IOS_WEB_FAVICON_DRIVER_H_