| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/favicon/favicon_tab_helper.h" |
| |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/favicon/favicon_handler.h" |
| #include "chrome/browser/favicon/favicon_service_factory.h" |
| #include "chrome/browser/favicon/favicon_util.h" |
| #include "chrome/browser/history/history_service.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 "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 "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); |
| |
| FaviconTabHelper::FaviconTabHelper(WebContents* web_contents) |
| : content::WebContentsObserver(web_contents), |
| profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())), |
| should_fetch_icons_(true) { |
| favicon_handler_.reset(new FaviconHandler(profile_, this, |
| FaviconHandler::FAVICON)); |
| if (chrome::kEnableTouchIcon) |
| touch_icon_handler_.reset(new FaviconHandler(profile_, this, |
| FaviconHandler::TOUCH)); |
| } |
| |
| FaviconTabHelper::~FaviconTabHelper() { |
| } |
| |
| void FaviconTabHelper::FetchFavicon(const GURL& url) { |
| if (!should_fetch_icons_) |
| return; |
| |
| favicon_handler_->FetchFavicon(url); |
| if (touch_icon_handler_.get()) |
| touch_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; |
| } |
| |
| bool FaviconTabHelper::ShouldDisplayFavicon() { |
| // Always display a throbber during pending loads. |
| const NavigationController& controller = web_contents()->GetController(); |
| if (controller.GetLastCommittedEntry() && controller.GetPendingEntry()) |
| return true; |
| |
| GURL url = web_contents()->GetURL(); |
| if (url.SchemeIs(chrome::kChromeUIScheme) && |
| url.host() == chrome::kChromeUINewTabHost) { |
| return false; |
| } |
| |
| // No favicon on Instant New Tab Pages. |
| if (chrome::IsInstantNTP(web_contents())) |
| return false; |
| |
| return true; |
| } |
| |
| void FaviconTabHelper::SaveFavicon() { |
| NavigationEntry* entry = web_contents()->GetController().GetActiveEntry(); |
| if (!entry || entry->GetURL().is_empty()) |
| return; |
| |
| // Make sure the page is in history, otherwise adding the favicon does |
| // nothing. |
| HistoryService* history = HistoryServiceFactory::GetForProfile( |
| profile_->GetOriginalProfile(), Profile::IMPLICIT_ACCESS); |
| if (!history) |
| return; |
| history->AddPageNoVisitForBookmark(entry->GetURL(), entry->GetTitle()); |
| |
| FaviconService* service = FaviconServiceFactory::GetForProfile( |
| profile_->GetOriginalProfile(), Profile::IMPLICIT_ACCESS); |
| if (!service) |
| return; |
| const FaviconStatus& favicon(entry->GetFavicon()); |
| if (!favicon.valid || favicon.url.is_empty() || |
| favicon.image.IsEmpty()) { |
| return; |
| } |
| service->SetFavicons( |
| entry->GetURL(), favicon.url, chrome::FAVICON, favicon.image); |
| } |
| |
| NavigationEntry* FaviconTabHelper::GetActiveEntry() { |
| return web_contents()->GetController().GetActiveEntry(); |
| } |
| |
| int FaviconTabHelper::StartDownload(const GURL& url, int max_image_size) { |
| FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( |
| profile_->GetOriginalProfile(), Profile::IMPLICIT_ACCESS); |
| if (favicon_service && favicon_service->WasUnableToDownloadFavicon(url)) { |
| DVLOG(1) << "Skip Failed FavIcon: " << url; |
| return 0; |
| } |
| |
| return web_contents()->DownloadImage( |
| url, |
| true, |
| max_image_size, |
| base::Bind(&FaviconTabHelper::DidDownloadFavicon,base::Unretained(this))); |
| } |
| |
| void FaviconTabHelper::NotifyFaviconUpdated(bool icon_url_changed) { |
| content::NotificationService::current()->Notify( |
| chrome::NOTIFICATION_FAVICON_UPDATED, |
| content::Source<WebContents>(web_contents()), |
| content::Details<bool>(&icon_url_changed)); |
| web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB); |
| } |
| |
| void FaviconTabHelper::DidStartNavigationToPendingEntry( |
| const GURL& url, |
| NavigationController::ReloadType reload_type) { |
| if (reload_type != NavigationController::NO_RELOAD && |
| !profile_->IsOffTheRecord()) { |
| FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( |
| profile_, Profile::IMPLICIT_ACCESS); |
| 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) { |
| // Get the favicon, either from history or request it from the net. |
| FetchFavicon(details.entry->GetURL()); |
| } |
| |
| void FaviconTabHelper::DidUpdateFaviconURL( |
| int32 page_id, |
| const std::vector<content::FaviconURL>& candidates) { |
| favicon_handler_->OnUpdateFaviconURL(page_id, candidates); |
| if (touch_icon_handler_.get()) |
| touch_icon_handler_->OnUpdateFaviconURL(page_id, candidates); |
| } |
| |
| 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; |
| FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( |
| profile_->GetOriginalProfile(), Profile::IMPLICIT_ACCESS); |
| 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); |
| } |
| } |