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.
5 #include "chrome/browser/favicon/favicon_tab_helper.h"
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"
31 using content::FaviconStatus
;
32 using content::NavigationController
;
33 using content::NavigationEntry
;
34 using content::WebContents
;
36 DEFINE_WEB_CONTENTS_USER_DATA_KEY(FaviconTabHelper
);
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
));
49 FaviconTabHelper::~FaviconTabHelper() {
52 void FaviconTabHelper::FetchFavicon(const GURL
& url
) {
53 if (!should_fetch_icons_
)
56 favicon_handler_
->FetchFavicon(url
);
57 if (touch_icon_handler_
.get())
58 touch_icon_handler_
->FetchFavicon(url
);
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();
67 return entry
->GetFavicon().image
;
69 entry
= controller
.GetLastCommittedEntry();
71 return entry
->GetFavicon().image
;
75 bool FaviconTabHelper::FaviconIsValid() const {
76 const NavigationController
& controller
= web_contents()->GetController();
77 NavigationEntry
* entry
= controller
.GetTransientEntry();
79 return entry
->GetFavicon().valid
;
81 entry
= controller
.GetLastCommittedEntry();
83 return entry
->GetFavicon().valid
;
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())
94 GURL url
= web_contents()->GetURL();
95 if (url
.SchemeIs(chrome::kChromeUIScheme
) &&
96 url
.host() == chrome::kChromeUINewTabHost
) {
100 // No favicon on Instant New Tab Pages.
101 if (chrome::IsInstantNTP(web_contents()))
107 void FaviconTabHelper::SaveFavicon() {
108 NavigationEntry
* entry
= web_contents()->GetController().GetActiveEntry();
109 if (!entry
|| entry
->GetURL().is_empty())
112 // Make sure the page is in history, otherwise adding the favicon does
114 HistoryService
* history
= HistoryServiceFactory::GetForProfile(
115 profile_
->GetOriginalProfile(), Profile::IMPLICIT_ACCESS
);
118 history
->AddPageNoVisitForBookmark(entry
->GetURL(), entry
->GetTitle());
120 FaviconService
* service
= FaviconServiceFactory::GetForProfile(
121 profile_
->GetOriginalProfile(), Profile::IMPLICIT_ACCESS
);
124 const FaviconStatus
& favicon(entry
->GetFavicon());
125 if (!favicon
.valid
|| favicon
.url
.is_empty() ||
126 favicon
.image
.IsEmpty()) {
129 service
->SetFavicons(
130 entry
->GetURL(), favicon
.url
, chrome::FAVICON
, favicon
.image
);
133 NavigationEntry
* FaviconTabHelper::GetActiveEntry() {
134 return web_contents()->GetController().GetActiveEntry();
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
;
145 return web_contents()->DownloadImage(
149 base::Bind(&FaviconTabHelper::DidDownloadFavicon
,base::Unretained(this)));
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
);
160 void FaviconTabHelper::DidStartNavigationToPendingEntry(
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();
175 void FaviconTabHelper::DidNavigateMainFrame(
176 const content::LoadCommittedDetails
& details
,
177 const content::FrameNavigateParams
& params
) {
178 favicon_urls_
.clear();
179 // Get the favicon, either from history or request it from the net.
180 FetchFavicon(details
.entry
->GetURL());
183 void FaviconTabHelper::DidUpdateFaviconURL(
185 const std::vector
<content::FaviconURL
>& candidates
) {
186 DCHECK(!candidates
.empty());
187 favicon_urls_
= candidates
;
189 favicon_handler_
->OnUpdateFaviconURL(page_id
, candidates
);
190 if (touch_icon_handler_
.get())
191 touch_icon_handler_
->OnUpdateFaviconURL(page_id
, candidates
);
194 void FaviconTabHelper::DidDownloadFavicon(
196 int http_status_code
,
197 const GURL
& image_url
,
198 const std::vector
<SkBitmap
>& bitmaps
,
199 const std::vector
<gfx::Size
>& original_bitmap_sizes
) {
201 if (bitmaps
.empty() && http_status_code
== 404) {
202 DVLOG(1) << "Failed to Download Favicon:" << image_url
;
203 FaviconService
* favicon_service
= FaviconServiceFactory::GetForProfile(
204 profile_
->GetOriginalProfile(), Profile::IMPLICIT_ACCESS
);
206 favicon_service
->UnableToDownloadFavicon(image_url
);
209 favicon_handler_
->OnDidDownloadFavicon(
210 id
, image_url
, bitmaps
, original_bitmap_sizes
);
211 if (touch_icon_handler_
.get()) {
212 touch_icon_handler_
->OnDidDownloadFavicon(
213 id
, image_url
, bitmaps
, original_bitmap_sizes
);