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 favicon_handler_
.reset(new FaviconHandler(profile_
, this,
42 FaviconHandler::FAVICON
));
43 if (chrome::kEnableTouchIcon
)
44 touch_icon_handler_
.reset(new FaviconHandler(profile_
, this,
45 FaviconHandler::TOUCH
));
48 FaviconTabHelper::~FaviconTabHelper() {
51 void FaviconTabHelper::FetchFavicon(const GURL
& url
) {
52 favicon_handler_
->FetchFavicon(url
);
53 if (touch_icon_handler_
.get())
54 touch_icon_handler_
->FetchFavicon(url
);
57 gfx::Image
FaviconTabHelper::GetFavicon() const {
58 // Like GetTitle(), we also want to use the favicon for the last committed
59 // entry rather than a pending navigation entry.
60 const NavigationController
& controller
= web_contents()->GetController();
61 NavigationEntry
* entry
= controller
.GetTransientEntry();
63 return entry
->GetFavicon().image
;
65 entry
= controller
.GetLastCommittedEntry();
67 return entry
->GetFavicon().image
;
71 bool FaviconTabHelper::FaviconIsValid() const {
72 const NavigationController
& controller
= web_contents()->GetController();
73 NavigationEntry
* entry
= controller
.GetTransientEntry();
75 return entry
->GetFavicon().valid
;
77 entry
= controller
.GetLastCommittedEntry();
79 return entry
->GetFavicon().valid
;
84 bool FaviconTabHelper::ShouldDisplayFavicon() {
85 // Always display a throbber during pending loads.
86 const NavigationController
& controller
= web_contents()->GetController();
87 if (controller
.GetLastCommittedEntry() && controller
.GetPendingEntry())
90 GURL url
= web_contents()->GetURL();
91 if (url
.SchemeIs(content::kChromeUIScheme
) &&
92 url
.host() == chrome::kChromeUINewTabHost
) {
96 // No favicon on Instant New Tab Pages.
97 if (chrome::IsInstantNTP(web_contents()))
103 void FaviconTabHelper::SaveFavicon() {
104 NavigationEntry
* entry
= web_contents()->GetController().GetActiveEntry();
105 if (!entry
|| entry
->GetURL().is_empty())
108 // Make sure the page is in history, otherwise adding the favicon does
110 HistoryService
* history
= HistoryServiceFactory::GetForProfile(
111 profile_
->GetOriginalProfile(), Profile::IMPLICIT_ACCESS
);
114 history
->AddPageNoVisitForBookmark(entry
->GetURL(), entry
->GetTitle());
116 FaviconService
* service
= FaviconServiceFactory::GetForProfile(
117 profile_
->GetOriginalProfile(), Profile::IMPLICIT_ACCESS
);
120 const FaviconStatus
& favicon(entry
->GetFavicon());
121 if (!favicon
.valid
|| favicon
.url
.is_empty() ||
122 favicon
.image
.IsEmpty()) {
125 service
->SetFavicons(
126 entry
->GetURL(), favicon
.url
, chrome::FAVICON
, favicon
.image
);
129 NavigationEntry
* FaviconTabHelper::GetActiveEntry() {
130 return web_contents()->GetController().GetActiveEntry();
133 int FaviconTabHelper::StartDownload(const GURL
& url
, int max_image_size
) {
134 FaviconService
* favicon_service
= FaviconServiceFactory::GetForProfile(
135 profile_
->GetOriginalProfile(), Profile::IMPLICIT_ACCESS
);
136 if (favicon_service
&& favicon_service
->WasUnableToDownloadFavicon(url
)) {
137 DVLOG(1) << "Skip Failed FavIcon: " << url
;
141 return web_contents()->DownloadImage(
145 base::Bind(&FaviconTabHelper::DidDownloadFavicon
,base::Unretained(this)));
148 void FaviconTabHelper::NotifyFaviconUpdated(bool icon_url_changed
) {
149 content::NotificationService::current()->Notify(
150 chrome::NOTIFICATION_FAVICON_UPDATED
,
151 content::Source
<WebContents
>(web_contents()),
152 content::Details
<bool>(&icon_url_changed
));
153 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB
);
156 void FaviconTabHelper::DidStartNavigationToPendingEntry(
158 NavigationController::ReloadType reload_type
) {
159 if (reload_type
!= NavigationController::NO_RELOAD
&&
160 !profile_
->IsOffTheRecord()) {
161 FaviconService
* favicon_service
= FaviconServiceFactory::GetForProfile(
162 profile_
, Profile::IMPLICIT_ACCESS
);
163 if (favicon_service
) {
164 favicon_service
->SetFaviconOutOfDateForPage(url
);
165 if (reload_type
== NavigationController::RELOAD_IGNORING_CACHE
)
166 favicon_service
->ClearUnableToDownloadFavicons();
171 void FaviconTabHelper::DidNavigateMainFrame(
172 const content::LoadCommittedDetails
& details
,
173 const content::FrameNavigateParams
& params
) {
174 favicon_urls_
.clear();
175 // Get the favicon, either from history or request it from the net.
176 FetchFavicon(details
.entry
->GetURL());
179 void FaviconTabHelper::DidUpdateFaviconURL(
181 const std::vector
<content::FaviconURL
>& candidates
) {
182 DCHECK(!candidates
.empty());
183 favicon_urls_
= candidates
;
185 favicon_handler_
->OnUpdateFaviconURL(page_id
, candidates
);
186 if (touch_icon_handler_
.get())
187 touch_icon_handler_
->OnUpdateFaviconURL(page_id
, candidates
);
190 void FaviconTabHelper::DidDownloadFavicon(
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
) {
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
);
202 favicon_service
->UnableToDownloadFavicon(image_url
);
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
);