1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/favicon/favicon_tab_helper.h" 6 7 #include "chrome/browser/chrome_notification_types.h" 8 #include "chrome/browser/favicon/favicon_handler.h" 9 #include "chrome/browser/favicon/favicon_service_factory.h" 10 #include "chrome/browser/favicon/favicon_util.h" 11 #include "chrome/browser/history/history_service.h" 12 #include "chrome/browser/history/history_service_factory.h" 13 #include "chrome/browser/profiles/profile.h" 14 #include "chrome/browser/search/search.h" 15 #include "chrome/common/chrome_constants.h" 16 #include "chrome/common/url_constants.h" 17 #include "content/public/browser/favicon_status.h" 18 #include "content/public/browser/invalidate_type.h" 19 #include "content/public/browser/navigation_controller.h" 20 #include "content/public/browser/navigation_details.h" 21 #include "content/public/browser/navigation_entry.h" 22 #include "content/public/browser/notification_service.h" 23 #include "content/public/browser/render_view_host.h" 24 #include "content/public/browser/web_contents.h" 25 #include "content/public/browser/web_contents_delegate.h" 26 #include "ui/gfx/codec/png_codec.h" 27 #include "ui/gfx/image/image.h" 28 #include "ui/gfx/image/image_skia.h" 29 #include "ui/gfx/image/image_skia_rep.h" 30 31 using content::FaviconStatus; 32 using content::NavigationController; 33 using content::NavigationEntry; 34 using content::WebContents; 35 36 DEFINE_WEB_CONTENTS_USER_DATA_KEY(FaviconTabHelper); 37 38 FaviconTabHelper::FaviconTabHelper(WebContents* web_contents) 39 : content::WebContentsObserver(web_contents), 40 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())), 41 should_fetch_icons_(true) { 42 favicon_handler_.reset(new FaviconHandler(profile_, this, 43 FaviconHandler::FAVICON)); 44 if (chrome::kEnableTouchIcon) 45 touch_icon_handler_.reset(new FaviconHandler(profile_, this, 46 FaviconHandler::TOUCH)); 47 } 48 49 FaviconTabHelper::~FaviconTabHelper() { 50 } 51 52 void FaviconTabHelper::FetchFavicon(const GURL& url) { 53 if (!should_fetch_icons_) 54 return; 55 56 favicon_handler_->FetchFavicon(url); 57 if (touch_icon_handler_.get()) 58 touch_icon_handler_->FetchFavicon(url); 59 } 60 61 gfx::Image FaviconTabHelper::GetFavicon() const { 62 // Like GetTitle(), we also want to use the favicon for the last committed 63 // entry rather than a pending navigation entry. 64 const NavigationController& controller = web_contents()->GetController(); 65 NavigationEntry* entry = controller.GetTransientEntry(); 66 if (entry) 67 return entry->GetFavicon().image; 68 69 entry = controller.GetLastCommittedEntry(); 70 if (entry) 71 return entry->GetFavicon().image; 72 return gfx::Image(); 73 } 74 75 bool FaviconTabHelper::FaviconIsValid() const { 76 const NavigationController& controller = web_contents()->GetController(); 77 NavigationEntry* entry = controller.GetTransientEntry(); 78 if (entry) 79 return entry->GetFavicon().valid; 80 81 entry = controller.GetLastCommittedEntry(); 82 if (entry) 83 return entry->GetFavicon().valid; 84 85 return false; 86 } 87 88 bool FaviconTabHelper::ShouldDisplayFavicon() { 89 // Always display a throbber during pending loads. 90 const NavigationController& controller = web_contents()->GetController(); 91 if (controller.GetLastCommittedEntry() && controller.GetPendingEntry()) 92 return true; 93 94 GURL url = web_contents()->GetURL(); 95 if (url.SchemeIs(chrome::kChromeUIScheme) && 96 url.host() == chrome::kChromeUINewTabHost) { 97 return false; 98 } 99 100 // No favicon on Instant New Tab Pages. 101 if (chrome::IsInstantNTP(web_contents())) 102 return false; 103 104 return true; 105 } 106 107 void FaviconTabHelper::SaveFavicon() { 108 NavigationEntry* entry = web_contents()->GetController().GetActiveEntry(); 109 if (!entry || entry->GetURL().is_empty()) 110 return; 111 112 // Make sure the page is in history, otherwise adding the favicon does 113 // nothing. 114 HistoryService* history = HistoryServiceFactory::GetForProfile( 115 profile_->GetOriginalProfile(), Profile::IMPLICIT_ACCESS); 116 if (!history) 117 return; 118 history->AddPageNoVisitForBookmark(entry->GetURL(), entry->GetTitle()); 119 120 FaviconService* service = FaviconServiceFactory::GetForProfile( 121 profile_->GetOriginalProfile(), Profile::IMPLICIT_ACCESS); 122 if (!service) 123 return; 124 const FaviconStatus& favicon(entry->GetFavicon()); 125 if (!favicon.valid || favicon.url.is_empty() || 126 favicon.image.IsEmpty()) { 127 return; 128 } 129 service->SetFavicons( 130 entry->GetURL(), favicon.url, chrome::FAVICON, favicon.image); 131 } 132 133 NavigationEntry* FaviconTabHelper::GetActiveEntry() { 134 return web_contents()->GetController().GetActiveEntry(); 135 } 136 137 int FaviconTabHelper::StartDownload(const GURL& url, 138 int preferred_image_size, 139 int max_image_size) { 140 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( 141 profile_->GetOriginalProfile(), Profile::IMPLICIT_ACCESS); 142 if (favicon_service && favicon_service->WasUnableToDownloadFavicon(url)) { 143 DVLOG(1) << "Skip Failed FavIcon: " << url; 144 return 0; 145 } 146 147 return web_contents()->DownloadImage( 148 url, 149 true, 150 preferred_image_size, 151 max_image_size, 152 base::Bind(&FaviconTabHelper::DidDownloadFavicon,base::Unretained(this))); 153 } 154 155 void FaviconTabHelper::NotifyFaviconUpdated(bool icon_url_changed) { 156 content::NotificationService::current()->Notify( 157 chrome::NOTIFICATION_FAVICON_UPDATED, 158 content::Source<WebContents>(web_contents()), 159 content::Details<bool>(&icon_url_changed)); 160 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB); 161 } 162 163 void FaviconTabHelper::NavigateToPendingEntry( 164 const GURL& url, 165 NavigationController::ReloadType reload_type) { 166 if (reload_type != NavigationController::NO_RELOAD && 167 !profile_->IsOffTheRecord()) { 168 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( 169 profile_, Profile::IMPLICIT_ACCESS); 170 if (favicon_service) { 171 favicon_service->SetFaviconOutOfDateForPage(url); 172 if (reload_type == NavigationController::RELOAD_IGNORING_CACHE) 173 favicon_service->ClearUnableToDownloadFavicons(); 174 } 175 } 176 } 177 178 void FaviconTabHelper::DidNavigateMainFrame( 179 const content::LoadCommittedDetails& details, 180 const content::FrameNavigateParams& params) { 181 // Get the favicon, either from history or request it from the net. 182 FetchFavicon(details.entry->GetURL()); 183 } 184 185 void FaviconTabHelper::DidUpdateFaviconURL( 186 int32 page_id, 187 const std::vector<content::FaviconURL>& candidates) { 188 favicon_handler_->OnUpdateFaviconURL(page_id, candidates); 189 if (touch_icon_handler_.get()) 190 touch_icon_handler_->OnUpdateFaviconURL(page_id, candidates); 191 } 192 193 void FaviconTabHelper::DidDownloadFavicon( 194 int id, 195 int http_status_code, 196 const GURL& image_url, 197 int requested_size, 198 const std::vector<SkBitmap>& bitmaps) { 199 200 if (bitmaps.empty() && http_status_code == 404) { 201 DVLOG(1) << "Failed to Download Favicon:" << image_url; 202 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( 203 profile_->GetOriginalProfile(), Profile::IMPLICIT_ACCESS); 204 if (favicon_service) 205 favicon_service->UnableToDownloadFavicon(image_url); 206 } 207 208 favicon_handler_->OnDidDownloadFavicon( 209 id, image_url, requested_size, bitmaps); 210 if (touch_icon_handler_.get()) { 211 touch_icon_handler_->OnDidDownloadFavicon( 212 id, image_url, requested_size, bitmaps); 213 } 214 } 215