diff options
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_ |