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, int max_image_size) { 138 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( 139 profile_->GetOriginalProfile(), Profile::IMPLICIT_ACCESS); 140 if (favicon_service && favicon_service->WasUnableToDownloadFavicon(url)) { 141 DVLOG(1) << "Skip Failed FavIcon: " << url; 142 return 0; 143 } 144 145 return web_contents()->DownloadImage( 146 url, 147 true, 148 max_image_size, 149 base::Bind(&FaviconTabHelper::DidDownloadFavicon,base::Unretained(this))); 150 } 151 152 void FaviconTabHelper::NotifyFaviconUpdated(bool icon_url_changed) { 153 content::NotificationService::current()->Notify( 154 chrome::NOTIFICATION_FAVICON_UPDATED, 155 content::Source<WebContents>(web_contents()), 156 content::Details<bool>(&icon_url_changed)); 157 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB); 158 } 159 160 void FaviconTabHelper::DidStartNavigationToPendingEntry( 161 const GURL& url, 162 NavigationController::ReloadType reload_type) { 163 if (reload_type != NavigationController::NO_RELOAD && 164 !profile_->IsOffTheRecord()) { 165 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( 166 profile_, Profile::IMPLICIT_ACCESS); 167 if (favicon_service) { 168 favicon_service->SetFaviconOutOfDateForPage(url); 169 if (reload_type == NavigationController::RELOAD_IGNORING_CACHE) 170 favicon_service->ClearUnableToDownloadFavicons(); 171 } 172 } 173 } 174 175 void FaviconTabHelper::DidNavigateMainFrame( 176 const content::LoadCommittedDetails& details, 177 const content::FrameNavigateParams& params) { 178 // Get the favicon, either from history or request it from the net. 179 FetchFavicon(details.entry->GetURL()); 180 } 181 182 void FaviconTabHelper::DidUpdateFaviconURL( 183 int32 page_id, 184 const std::vector<content::FaviconURL>& candidates) { 185 favicon_handler_->OnUpdateFaviconURL(page_id, candidates); 186 if (touch_icon_handler_.get()) 187 touch_icon_handler_->OnUpdateFaviconURL(page_id, candidates); 188 } 189 190 void FaviconTabHelper::DidDownloadFavicon( 191 int id, 192 int http_status_code, 193 const GURL& image_url, 194 const std::vector<SkBitmap>& bitmaps, 195 const std::vector<gfx::Size>& original_bitmap_sizes) { 196 197 if (bitmaps.empty() && http_status_code == 404) { 198 DVLOG(1) << "Failed to Download Favicon:" << image_url; 199 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( 200 profile_->GetOriginalProfile(), Profile::IMPLICIT_ACCESS); 201 if (favicon_service) 202 favicon_service->UnableToDownloadFavicon(image_url); 203 } 204 205 favicon_handler_->OnDidDownloadFavicon( 206 id, image_url, bitmaps, original_bitmap_sizes); 207 if (touch_icon_handler_.get()) { 208 touch_icon_handler_->OnDidDownloadFavicon( 209 id, image_url, bitmaps, original_bitmap_sizes); 210 } 211 } 212