Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / favicon / favicon_tab_helper.cc
blob3992f8f02aca60b86bc066008245594ad18c5a90
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/chrome_favicon_client.h"
9 #include "chrome/browser/favicon/chrome_favicon_client_factory.h"
10 #include "chrome/browser/favicon/favicon_handler.h"
11 #include "chrome/browser/favicon/favicon_service.h"
12 #include "chrome/browser/favicon/favicon_service_factory.h"
13 #include "chrome/browser/history/history_service.h"
14 #include "chrome/browser/history/history_service_factory.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/search/search.h"
17 #include "chrome/common/chrome_constants.h"
18 #include "chrome/common/url_constants.h"
19 #include "components/favicon_base/favicon_types.h"
20 #include "content/public/browser/favicon_status.h"
21 #include "content/public/browser/invalidate_type.h"
22 #include "content/public/browser/navigation_controller.h"
23 #include "content/public/browser/navigation_details.h"
24 #include "content/public/browser/navigation_entry.h"
25 #include "content/public/browser/notification_service.h"
26 #include "content/public/browser/render_view_host.h"
27 #include "content/public/browser/web_contents.h"
28 #include "content/public/browser/web_contents_delegate.h"
29 #include "content/public/common/favicon_url.h"
30 #include "ui/gfx/codec/png_codec.h"
31 #include "ui/gfx/image/image.h"
32 #include "ui/gfx/image/image_skia.h"
33 #include "ui/gfx/image/image_skia_rep.h"
35 using content::FaviconStatus;
36 using content::NavigationController;
37 using content::NavigationEntry;
38 using content::WebContents;
40 DEFINE_WEB_CONTENTS_USER_DATA_KEY(FaviconTabHelper);
42 FaviconTabHelper::FaviconTabHelper(WebContents* web_contents)
43 : content::WebContentsObserver(web_contents),
44 profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())) {
45 client_ = ChromeFaviconClientFactory::GetForProfile(profile_);
46 #if defined(OS_ANDROID) || defined(OS_IOS)
47 bool download_largest_icon = true;
48 #else
49 bool download_largest_icon = false;
50 #endif
51 favicon_handler_.reset(new FaviconHandler(
52 client_, this, FaviconHandler::FAVICON, download_largest_icon));
53 if (chrome::kEnableTouchIcon)
54 touch_icon_handler_.reset(new FaviconHandler(
55 client_, this, FaviconHandler::TOUCH, download_largest_icon));
58 FaviconTabHelper::~FaviconTabHelper() {
61 void FaviconTabHelper::FetchFavicon(const GURL& url) {
62 favicon_handler_->FetchFavicon(url);
63 if (touch_icon_handler_.get())
64 touch_icon_handler_->FetchFavicon(url);
67 gfx::Image FaviconTabHelper::GetFavicon() const {
68 // Like GetTitle(), we also want to use the favicon for the last committed
69 // entry rather than a pending navigation entry.
70 const NavigationController& controller = web_contents()->GetController();
71 NavigationEntry* entry = controller.GetTransientEntry();
72 if (entry)
73 return entry->GetFavicon().image;
75 entry = controller.GetLastCommittedEntry();
76 if (entry)
77 return entry->GetFavicon().image;
78 return gfx::Image();
81 bool FaviconTabHelper::FaviconIsValid() const {
82 const NavigationController& controller = web_contents()->GetController();
83 NavigationEntry* entry = controller.GetTransientEntry();
84 if (entry)
85 return entry->GetFavicon().valid;
87 entry = controller.GetLastCommittedEntry();
88 if (entry)
89 return entry->GetFavicon().valid;
91 return false;
94 bool FaviconTabHelper::ShouldDisplayFavicon() {
95 // Always display a throbber during pending loads.
96 const NavigationController& controller = web_contents()->GetController();
97 if (controller.GetLastCommittedEntry() && controller.GetPendingEntry())
98 return true;
100 GURL url = web_contents()->GetURL();
101 if (url.SchemeIs(content::kChromeUIScheme) &&
102 url.host() == chrome::kChromeUINewTabHost) {
103 return false;
106 // No favicon on Instant New Tab Pages.
107 if (chrome::IsInstantNTP(web_contents()))
108 return false;
110 return true;
113 void FaviconTabHelper::SaveFavicon() {
114 NavigationEntry* entry = web_contents()->GetController().GetActiveEntry();
115 if (!entry || entry->GetURL().is_empty())
116 return;
118 // Make sure the page is in history, otherwise adding the favicon does
119 // nothing.
120 HistoryService* history = HistoryServiceFactory::GetForProfile(
121 profile_->GetOriginalProfile(), Profile::IMPLICIT_ACCESS);
122 if (!history)
123 return;
124 history->AddPageNoVisitForBookmark(entry->GetURL(), entry->GetTitle());
126 FaviconService* service = FaviconServiceFactory::GetForProfile(
127 profile_->GetOriginalProfile(), Profile::IMPLICIT_ACCESS);
128 if (!service)
129 return;
130 const FaviconStatus& favicon(entry->GetFavicon());
131 if (!favicon.valid || favicon.url.is_empty() ||
132 favicon.image.IsEmpty()) {
133 return;
135 service->SetFavicons(
136 entry->GetURL(), favicon.url, favicon_base::FAVICON, favicon.image);
139 int FaviconTabHelper::StartDownload(const GURL& url, 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;
147 return web_contents()->DownloadImage(
148 url,
149 true,
150 max_image_size,
151 base::Bind(&FaviconTabHelper::DidDownloadFavicon,base::Unretained(this)));
154 void FaviconTabHelper::NotifyFaviconUpdated(bool icon_url_changed) {
155 content::NotificationService::current()->Notify(
156 chrome::NOTIFICATION_FAVICON_UPDATED,
157 content::Source<WebContents>(web_contents()),
158 content::Details<bool>(&icon_url_changed));
159 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
162 bool FaviconTabHelper::IsOffTheRecord() {
163 DCHECK(web_contents());
164 return web_contents()->GetBrowserContext()->IsOffTheRecord();
167 const gfx::Image FaviconTabHelper::GetActiveFaviconImage() {
168 return GetFaviconStatus().image;
171 const GURL FaviconTabHelper::GetActiveFaviconURL() {
172 return GetFaviconStatus().url;
175 bool FaviconTabHelper::GetActiveFaviconValidity() {
176 return GetFaviconStatus().valid;
179 const GURL FaviconTabHelper::GetActiveURL() {
180 NavigationEntry* entry = web_contents()->GetController().GetActiveEntry();
181 if (!entry || entry->GetURL().is_empty())
182 return GURL();
183 return entry->GetURL();
186 void FaviconTabHelper::SetActiveFaviconImage(gfx::Image image) {
187 GetFaviconStatus().image = image;
190 void FaviconTabHelper::SetActiveFaviconURL(GURL url) {
191 GetFaviconStatus().url = url;
194 void FaviconTabHelper::SetActiveFaviconValidity(bool validity) {
195 GetFaviconStatus().valid = validity;
198 content::FaviconStatus& FaviconTabHelper::GetFaviconStatus() {
199 DCHECK(web_contents()->GetController().GetActiveEntry());
200 return web_contents()->GetController().GetActiveEntry()->GetFavicon();
203 void FaviconTabHelper::DidStartNavigationToPendingEntry(
204 const GURL& url,
205 NavigationController::ReloadType reload_type) {
206 if (reload_type != NavigationController::NO_RELOAD &&
207 !profile_->IsOffTheRecord()) {
208 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile(
209 profile_, Profile::IMPLICIT_ACCESS);
210 if (favicon_service) {
211 favicon_service->SetFaviconOutOfDateForPage(url);
212 if (reload_type == NavigationController::RELOAD_IGNORING_CACHE)
213 favicon_service->ClearUnableToDownloadFavicons();
218 void FaviconTabHelper::DidNavigateMainFrame(
219 const content::LoadCommittedDetails& details,
220 const content::FrameNavigateParams& params) {
221 favicon_urls_.clear();
222 // Get the favicon, either from history or request it from the net.
223 FetchFavicon(details.entry->GetURL());
226 // Returns favicon_base::IconType the given icon_type corresponds to.
227 // TODO(jif): Move function to /components/favicon_base/content/
228 // crbug.com/374281.
229 favicon_base::IconType ToChromeIconType(
230 content::FaviconURL::IconType icon_type) {
231 switch (icon_type) {
232 case content::FaviconURL::FAVICON:
233 return favicon_base::FAVICON;
234 case content::FaviconURL::TOUCH_ICON:
235 return favicon_base::TOUCH_ICON;
236 case content::FaviconURL::TOUCH_PRECOMPOSED_ICON:
237 return favicon_base::TOUCH_PRECOMPOSED_ICON;
238 case content::FaviconURL::INVALID_ICON:
239 return favicon_base::INVALID_ICON;
241 NOTREACHED();
242 return favicon_base::INVALID_ICON;
245 void FaviconTabHelper::DidUpdateFaviconURL(
246 const std::vector<content::FaviconURL>& candidates) {
247 DCHECK(!candidates.empty());
248 favicon_urls_ = candidates;
249 std::vector<favicon::FaviconURL> favicon_urls;
250 for (size_t i = 0; i < candidates.size(); i++) {
251 const content::FaviconURL& candidate = candidates[i];
252 favicon_urls.push_back(
253 favicon::FaviconURL(candidate.icon_url,
254 ToChromeIconType(candidate.icon_type),
255 candidate.icon_sizes));
257 favicon_handler_->OnUpdateFaviconURL(favicon_urls);
258 if (touch_icon_handler_.get())
259 touch_icon_handler_->OnUpdateFaviconURL(favicon_urls);
262 void FaviconTabHelper::DidDownloadFavicon(
263 int id,
264 int http_status_code,
265 const GURL& image_url,
266 const std::vector<SkBitmap>& bitmaps,
267 const std::vector<gfx::Size>& original_bitmap_sizes) {
269 if (bitmaps.empty() && http_status_code == 404) {
270 DVLOG(1) << "Failed to Download Favicon:" << image_url;
271 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile(
272 profile_->GetOriginalProfile(), Profile::IMPLICIT_ACCESS);
273 if (favicon_service)
274 favicon_service->UnableToDownloadFavicon(image_url);
277 favicon_handler_->OnDidDownloadFavicon(
278 id, image_url, bitmaps, original_bitmap_sizes);
279 if (touch_icon_handler_.get()) {
280 touch_icon_handler_->OnDidDownloadFavicon(
281 id, image_url, bitmaps, original_bitmap_sizes);