summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsdefresne <sdefresne@chromium.org>2015-04-09 07:00:17 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-09 14:00:45 +0000
commit70a04802728cbdc0c3da3c5a43fd2aa6feaf1ca8 (patch)
tree55cc56a7d0edc3766846d9467519877b1a81f45b
parent181fd73aa111fff257616435820a6392e309a5e5 (diff)
downloadchromium_src-70a04802728cbdc0c3da3c5a43fd2aa6feaf1ca8.zip
chromium_src-70a04802728cbdc0c3da3c5a43fd2aa6feaf1ca8.tar.gz
chromium_src-70a04802728cbdc0c3da3c5a43fd2aa6feaf1ca8.tar.bz2
Componentize FaviconTabHelper
Split FaviconTabHelper into three classes depending on what can be shared with iOS (FaviconDriverImpl), what only depends on //content (ContentFaviconDriver) and what depends on //chrome (FaviconTabHelper). FaviconTabHelper still exists to provide an easier factory (as ContentFaviconDriver cannot access KeyedService factories defined in //chrome) as FaviconTabHelper::CreateForWebContents() is called from multiple locations in //chrome code and to provide an implementation for FaviconTabHelper::ShouldDisplayFavicon (this method will be turned into a free function in a followup CL as it only depends on WebContents public interface, not on ContentFaviconDriver). Introduce WebFaviconDriver, an iOS implementation of FaviconDriver that uses FaviconDriverImpl to share as much code as possible with the ContentFaviconDriver. BUG=370877, 472117 Review URL: https://codereview.chromium.org/1064823002 Cr-Commit-Position: refs/heads/master@{#324430}
-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_