Make castv2 performance test work.
[chromium-blink-merge.git] / chrome / browser / favicon / favicon_tab_helper.cc
blob8832076f92ffe0732588f11937d8ed1453c4b622
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 "base/command_line.h"
8 #include "base/metrics/field_trial.h"
9 #include "base/strings/string_util.h"
10 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/favicon/favicon_service_factory.h"
13 #include "chrome/browser/history/history_service_factory.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/search/search.h"
16 #include "chrome/common/chrome_constants.h"
17 #include "chrome/common/url_constants.h"
18 #include "components/bookmarks/browser/bookmark_model.h"
19 #include "components/favicon/content/favicon_url_util.h"
20 #include "components/favicon/core/favicon_driver_observer.h"
21 #include "components/favicon/core/favicon_handler.h"
22 #include "components/favicon/core/favicon_service.h"
23 #include "components/favicon_base/favicon_types.h"
24 #include "components/history/core/browser/history_service.h"
25 #include "content/public/browser/favicon_status.h"
26 #include "content/public/browser/invalidate_type.h"
27 #include "content/public/browser/navigation_controller.h"
28 #include "content/public/browser/navigation_details.h"
29 #include "content/public/browser/navigation_entry.h"
30 #include "content/public/browser/notification_service.h"
31 #include "content/public/browser/render_view_host.h"
32 #include "content/public/browser/web_contents.h"
33 #include "content/public/browser/web_contents_delegate.h"
34 #include "content/public/common/favicon_url.h"
35 #include "ui/base/ui_base_switches.h"
36 #include "ui/gfx/codec/png_codec.h"
37 #include "ui/gfx/image/image.h"
38 #include "ui/gfx/image/image_skia.h"
39 #include "ui/gfx/image/image_skia_rep.h"
41 using content::FaviconStatus;
42 using content::NavigationController;
43 using content::NavigationEntry;
44 using content::WebContents;
46 DEFINE_WEB_CONTENTS_USER_DATA_KEY(FaviconTabHelper);
48 namespace {
50 // Returns whether icon NTP is enabled by experiment.
51 // TODO(huangs): Remove all 3 copies of this routine once Icon NTP launches.
52 bool IsIconNTPEnabled() {
53 // Note: It's important to query the field trial state first, to ensure that
54 // UMA reports the correct group.
55 const std::string group_name = base::FieldTrialList::FindFullName("IconNTP");
56 using base::CommandLine;
57 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDisableIconNtp))
58 return false;
59 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableIconNtp))
60 return true;
62 return StartsWithASCII(group_name, "Enabled", true);
65 #if defined(OS_ANDROID) || defined(OS_IOS)
66 const bool kDownloadLargestIcon = true;
67 const bool kEnableTouchIcon = true;
68 #else
69 const bool kDownloadLargestIcon = false;
70 const bool kEnableTouchIcon = false;
71 #endif
73 } // namespace
75 // static
76 void FaviconTabHelper::CreateForWebContents(
77 content::WebContents* web_contents) {
78 DCHECK(web_contents);
79 if (FromWebContents(web_contents))
80 return;
82 Profile* original_profile =
83 Profile::FromBrowserContext(web_contents->GetBrowserContext())
84 ->GetOriginalProfile();
85 web_contents->SetUserData(
86 UserDataKey(),
87 new FaviconTabHelper(
88 web_contents,
89 FaviconServiceFactory::GetForProfile(
90 original_profile, ServiceAccessType::IMPLICIT_ACCESS),
91 HistoryServiceFactory::GetForProfile(
92 original_profile, ServiceAccessType::IMPLICIT_ACCESS),
93 BookmarkModelFactory::GetForProfileIfExists(original_profile)));
96 FaviconTabHelper::FaviconTabHelper(WebContents* web_contents,
97 favicon::FaviconService* favicon_service,
98 history::HistoryService* history_service,
99 bookmarks::BookmarkModel* bookmark_model)
100 : content::WebContentsObserver(web_contents),
101 favicon_service_(favicon_service),
102 history_service_(history_service),
103 bookmark_model_(bookmark_model) {
104 favicon_handler_.reset(new favicon::FaviconHandler(
105 favicon_service_, this, favicon::FaviconHandler::FAVICON,
106 kDownloadLargestIcon));
107 if (kEnableTouchIcon) {
108 touch_icon_handler_.reset(new favicon::FaviconHandler(
109 favicon_service_, this, favicon::FaviconHandler::TOUCH,
110 kDownloadLargestIcon));
112 if (IsIconNTPEnabled()) {
113 large_icon_handler_.reset(new favicon::FaviconHandler(
114 favicon_service_, this, favicon::FaviconHandler::LARGE, true));
118 FaviconTabHelper::~FaviconTabHelper() {
121 void FaviconTabHelper::FetchFavicon(const GURL& url) {
122 favicon_handler_->FetchFavicon(url);
123 if (touch_icon_handler_.get())
124 touch_icon_handler_->FetchFavicon(url);
125 if (large_icon_handler_.get())
126 large_icon_handler_->FetchFavicon(url);
129 gfx::Image FaviconTabHelper::GetFavicon() const {
130 // Like GetTitle(), we also want to use the favicon for the last committed
131 // entry rather than a pending navigation entry.
132 const NavigationController& controller = web_contents()->GetController();
133 NavigationEntry* entry = controller.GetTransientEntry();
134 if (entry)
135 return entry->GetFavicon().image;
137 entry = controller.GetLastCommittedEntry();
138 if (entry)
139 return entry->GetFavicon().image;
140 return gfx::Image();
143 bool FaviconTabHelper::FaviconIsValid() const {
144 const NavigationController& controller = web_contents()->GetController();
145 NavigationEntry* entry = controller.GetTransientEntry();
146 if (entry)
147 return entry->GetFavicon().valid;
149 entry = controller.GetLastCommittedEntry();
150 if (entry)
151 return entry->GetFavicon().valid;
153 return false;
156 bool FaviconTabHelper::ShouldDisplayFavicon() {
157 // Always display a throbber during pending loads.
158 const NavigationController& controller = web_contents()->GetController();
159 if (controller.GetLastCommittedEntry() && controller.GetPendingEntry())
160 return true;
162 GURL url = web_contents()->GetURL();
163 if (url.SchemeIs(content::kChromeUIScheme) &&
164 url.host() == chrome::kChromeUINewTabHost) {
165 return false;
168 // No favicon on Instant New Tab Pages.
169 if (chrome::IsInstantNTP(web_contents()))
170 return false;
172 return true;
175 void FaviconTabHelper::SaveFavicon() {
176 GURL active_url = GetActiveURL();
177 if (active_url.is_empty())
178 return;
180 // Make sure the page is in history, otherwise adding the favicon does
181 // nothing.
182 if (!history_service_)
183 return;
184 history_service_->AddPageNoVisitForBookmark(active_url, GetActiveTitle());
186 if (!favicon_service_)
187 return;
188 if (!GetActiveFaviconValidity())
189 return;
190 GURL favicon_url = GetActiveFaviconURL();
191 if (favicon_url.is_empty())
192 return;
193 gfx::Image image = GetActiveFaviconImage();
194 if (image.IsEmpty())
195 return;
196 favicon_service_->SetFavicons(active_url, favicon_url, favicon_base::FAVICON,
197 image);
200 void FaviconTabHelper::AddObserver(favicon::FaviconDriverObserver* observer) {
201 observer_list_.AddObserver(observer);
204 void FaviconTabHelper::RemoveObserver(
205 favicon::FaviconDriverObserver* observer) {
206 observer_list_.RemoveObserver(observer);
209 int FaviconTabHelper::StartDownload(const GURL& url, int max_image_size) {
210 if (favicon_service_ && favicon_service_->WasUnableToDownloadFavicon(url)) {
211 DVLOG(1) << "Skip Failed FavIcon: " << url;
212 return 0;
215 bool bypass_cache = (bypass_cache_page_url_ == GetActiveURL());
216 bypass_cache_page_url_ = GURL();
218 return web_contents()->DownloadImage(
219 url, true, max_image_size, bypass_cache,
220 base::Bind(&FaviconTabHelper::DidDownloadFavicon,
221 base::Unretained(this)));
224 bool FaviconTabHelper::IsOffTheRecord() {
225 DCHECK(web_contents());
226 return web_contents()->GetBrowserContext()->IsOffTheRecord();
229 bool FaviconTabHelper::IsBookmarked(const GURL& url) {
230 return bookmark_model_ && bookmark_model_->IsBookmarked(url);
233 GURL FaviconTabHelper::GetActiveURL() {
234 NavigationEntry* entry = web_contents()->GetController().GetActiveEntry();
235 return entry ? entry->GetURL() : GURL();
238 base::string16 FaviconTabHelper::GetActiveTitle() {
239 NavigationEntry* entry = web_contents()->GetController().GetActiveEntry();
240 return entry ? entry->GetTitle() : base::string16();
243 bool FaviconTabHelper::GetActiveFaviconValidity() {
244 return GetFaviconStatus().valid;
247 void FaviconTabHelper::SetActiveFaviconValidity(bool valid) {
248 GetFaviconStatus().valid = valid;
251 GURL FaviconTabHelper::GetActiveFaviconURL() {
252 return GetFaviconStatus().url;
255 void FaviconTabHelper::SetActiveFaviconURL(const GURL& url) {
256 GetFaviconStatus().url = url;
259 gfx::Image FaviconTabHelper::GetActiveFaviconImage() {
260 return GetFaviconStatus().image;
263 void FaviconTabHelper::SetActiveFaviconImage(const gfx::Image& image) {
264 GetFaviconStatus().image = image;
267 void FaviconTabHelper::OnFaviconAvailable(const gfx::Image& image,
268 const GURL& icon_url,
269 bool is_active_favicon) {
270 if (is_active_favicon) {
271 // No matter what happens, we need to mark the favicon as being set.
272 SetActiveFaviconValidity(true);
273 bool icon_url_changed = GetActiveFaviconURL() != icon_url;
274 SetActiveFaviconURL(icon_url);
276 if (image.IsEmpty())
277 return;
279 SetActiveFaviconImage(image);
280 content::NotificationService::current()->Notify(
281 chrome::NOTIFICATION_FAVICON_UPDATED,
282 content::Source<WebContents>(web_contents()),
283 content::Details<bool>(&icon_url_changed));
284 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
286 if (!image.IsEmpty()) {
287 FOR_EACH_OBSERVER(favicon::FaviconDriverObserver, observer_list_,
288 OnFaviconAvailable(image));
292 void FaviconTabHelper::DidDownloadFavicon(
293 int id,
294 int http_status_code,
295 const GURL& image_url,
296 const std::vector<SkBitmap>& bitmaps,
297 const std::vector<gfx::Size>& original_bitmap_sizes) {
298 if (bitmaps.empty() && http_status_code == 404) {
299 DVLOG(1) << "Failed to Download Favicon:" << image_url;
300 if (favicon_service_)
301 favicon_service_->UnableToDownloadFavicon(image_url);
304 favicon_handler_->OnDidDownloadFavicon(id, image_url, bitmaps,
305 original_bitmap_sizes);
306 if (touch_icon_handler_.get()) {
307 touch_icon_handler_->OnDidDownloadFavicon(id, image_url, bitmaps,
308 original_bitmap_sizes);
310 if (large_icon_handler_.get()) {
311 large_icon_handler_->OnDidDownloadFavicon(id, image_url, bitmaps,
312 original_bitmap_sizes);
316 content::FaviconStatus& FaviconTabHelper::GetFaviconStatus() {
317 DCHECK(web_contents()->GetController().GetActiveEntry());
318 return web_contents()->GetController().GetActiveEntry()->GetFavicon();
321 void FaviconTabHelper::DidStartNavigationToPendingEntry(
322 const GURL& url,
323 NavigationController::ReloadType reload_type) {
324 if (reload_type == NavigationController::NO_RELOAD || IsOffTheRecord())
325 return;
327 bypass_cache_page_url_ = url;
329 if (favicon_service_) {
330 favicon_service_->SetFaviconOutOfDateForPage(url);
331 if (reload_type == NavigationController::RELOAD_IGNORING_CACHE)
332 favicon_service_->ClearUnableToDownloadFavicons();
336 void FaviconTabHelper::DidNavigateMainFrame(
337 const content::LoadCommittedDetails& details,
338 const content::FrameNavigateParams& params) {
339 favicon_urls_.clear();
341 // Wait till the user navigates to a new URL to start checking the cache
342 // again. The cache may be ignored for non-reload navigations (e.g.
343 // history.replace() in-page navigation). This is allowed to increase the
344 // likelihood that "reloading a page ignoring the cache" redownloads the
345 // favicon. In particular, a page may do an in-page navigation before
346 // FaviconHandler has the time to determine that the favicon needs to be
347 // redownloaded.
348 GURL url = details.entry->GetURL();
349 if (url != bypass_cache_page_url_)
350 bypass_cache_page_url_ = GURL();
352 // Get the favicon, either from history or request it from the net.
353 FetchFavicon(url);
356 void FaviconTabHelper::DidUpdateFaviconURL(
357 const std::vector<content::FaviconURL>& candidates) {
358 DCHECK(!candidates.empty());
359 favicon_urls_ = candidates;
360 std::vector<favicon::FaviconURL> favicon_urls =
361 favicon::FaviconURLsFromContentFaviconURLs(candidates);
362 favicon_handler_->OnUpdateFaviconURL(favicon_urls);
363 if (touch_icon_handler_.get())
364 touch_icon_handler_->OnUpdateFaviconURL(favicon_urls);
365 if (large_icon_handler_.get())
366 large_icon_handler_->OnUpdateFaviconURL(favicon_urls);