Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(873)

Side by Side Diff: chrome/browser/favicon/favicon_tab_helper.cc

Issue 1064823002: Componentize FaviconTabHelper (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@favicon-notification
Patch Set: Fix BUILD.gn Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/favicon/favicon_tab_helper.h" 5 #include "chrome/browser/favicon/favicon_tab_helper.h"
6 6
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" 7 #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" 8 #include "chrome/browser/favicon/favicon_service_factory.h"
13 #include "chrome/browser/history/history_service_factory.h" 9 #include "chrome/browser/history/history_service_factory.h"
14 #include "chrome/browser/profiles/profile.h" 10 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/search/search.h" 11 #include "chrome/browser/search/search.h"
16 #include "chrome/common/chrome_constants.h"
17 #include "chrome/common/url_constants.h" 12 #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" 13 #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"
40
41 using content::FaviconStatus;
42 using content::NavigationController;
43 using content::NavigationEntry;
44 using content::WebContents;
45
46 DEFINE_WEB_CONTENTS_USER_DATA_KEY(FaviconTabHelper);
47
48 namespace {
49
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;
61
62 return StartsWithASCII(group_name, "Enabled", true);
63 }
64
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
72
73 } // namespace
74 14
75 // static 15 // static
76 void FaviconTabHelper::CreateForWebContents( 16 void FaviconTabHelper::CreateForWebContents(
77 content::WebContents* web_contents) { 17 content::WebContents* web_contents) {
78 DCHECK(web_contents); 18 DCHECK(web_contents);
79 if (FromWebContents(web_contents)) 19 if (FromWebContents(web_contents))
80 return; 20 return;
81 21
82 Profile* original_profile = 22 Profile* original_profile =
83 Profile::FromBrowserContext(web_contents->GetBrowserContext()) 23 Profile::FromBrowserContext(web_contents->GetBrowserContext())
84 ->GetOriginalProfile(); 24 ->GetOriginalProfile();
85 web_contents->SetUserData( 25 web_contents->SetUserData(
86 UserDataKey(), 26 UserDataKey(),
87 new FaviconTabHelper( 27 new FaviconTabHelper(
88 web_contents, 28 web_contents,
89 FaviconServiceFactory::GetForProfile( 29 FaviconServiceFactory::GetForProfile(
90 original_profile, ServiceAccessType::IMPLICIT_ACCESS), 30 original_profile, ServiceAccessType::IMPLICIT_ACCESS),
91 HistoryServiceFactory::GetForProfile( 31 HistoryServiceFactory::GetForProfile(
92 original_profile, ServiceAccessType::IMPLICIT_ACCESS), 32 original_profile, ServiceAccessType::IMPLICIT_ACCESS),
93 BookmarkModelFactory::GetForProfileIfExists(original_profile))); 33 BookmarkModelFactory::GetForProfileIfExists(original_profile)));
94 } 34 }
95 35
96 FaviconTabHelper::FaviconTabHelper(WebContents* web_contents, 36 // static
97 favicon::FaviconService* favicon_service, 37 FaviconTabHelper* FaviconTabHelper::FromWebContents(
98 history::HistoryService* history_service, 38 content::WebContents* web_contents) {
99 bookmarks::BookmarkModel* bookmark_model) 39 return static_cast<FaviconTabHelper*>(
100 : content::WebContentsObserver(web_contents), 40 favicon::ContentFaviconDriver::FromWebContents(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));
111 }
112 if (IsIconNTPEnabled()) {
113 large_icon_handler_.reset(new favicon::FaviconHandler(
114 favicon_service_, this, favicon::FaviconHandler::LARGE, true));
115 }
116 } 41 }
117 42
118 FaviconTabHelper::~FaviconTabHelper() { 43 // static
119 } 44 bool FaviconTabHelper::ShouldDisplayFavicon(
120 45 content::WebContents* web_contents) {
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);
127 }
128
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;
136
137 entry = controller.GetLastCommittedEntry();
138 if (entry)
139 return entry->GetFavicon().image;
140 return gfx::Image();
141 }
142
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;
148
149 entry = controller.GetLastCommittedEntry();
150 if (entry)
151 return entry->GetFavicon().valid;
152
153 return false;
154 }
155
156 bool FaviconTabHelper::ShouldDisplayFavicon() {
157 // Always display a throbber during pending loads. 46 // Always display a throbber during pending loads.
158 const NavigationController& controller = web_contents()->GetController(); 47 const content::NavigationController& controller =
48 web_contents->GetController();
159 if (controller.GetLastCommittedEntry() && controller.GetPendingEntry()) 49 if (controller.GetLastCommittedEntry() && controller.GetPendingEntry())
160 return true; 50 return true;
161 51
162 GURL url = web_contents()->GetURL(); 52 GURL url = web_contents->GetURL();
163 if (url.SchemeIs(content::kChromeUIScheme) && 53 if (url.SchemeIs(content::kChromeUIScheme) &&
164 url.host() == chrome::kChromeUINewTabHost) { 54 url.host() == chrome::kChromeUINewTabHost) {
165 return false; 55 return false;
166 } 56 }
167 57
168 // No favicon on Instant New Tab Pages. 58 // No favicon on Instant New Tab Pages.
169 if (chrome::IsInstantNTP(web_contents())) 59 if (chrome::IsInstantNTP(web_contents))
170 return false; 60 return false;
171 61
172 return true; 62 return true;
173 } 63 }
174 64
175 void FaviconTabHelper::SaveFavicon() { 65 FaviconTabHelper::FaviconTabHelper(content::WebContents* web_contents,
176 GURL active_url = GetActiveURL(); 66 favicon::FaviconService* favicon_service,
177 if (active_url.is_empty()) 67 history::HistoryService* history_service,
178 return; 68 bookmarks::BookmarkModel* bookmark_model)
179 69 : favicon::ContentFaviconDriver(web_contents,
180 // Make sure the page is in history, otherwise adding the favicon does 70 favicon_service,
181 // nothing. 71 history_service,
182 if (!history_service_) 72 bookmark_model) {
183 return;
184 history_service_->AddPageNoVisitForBookmark(active_url, GetActiveTitle());
185
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);
198 } 73 }
199
200 void FaviconTabHelper::AddObserver(favicon::FaviconDriverObserver* observer) {
201 observer_list_.AddObserver(observer);
202 }
203
204 void FaviconTabHelper::RemoveObserver(
205 favicon::FaviconDriverObserver* observer) {
206 observer_list_.RemoveObserver(observer);
207 }
208
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;
213 }
214
215 bool bypass_cache = (bypass_cache_page_url_ == GetActiveURL());
216 bypass_cache_page_url_ = GURL();
217
218 return web_contents()->DownloadImage(
219 url, true, max_image_size, bypass_cache,
220 base::Bind(&FaviconTabHelper::DidDownloadFavicon,
221 base::Unretained(this)));
222 }
223
224 bool FaviconTabHelper::IsOffTheRecord() {
225 DCHECK(web_contents());
226 return web_contents()->GetBrowserContext()->IsOffTheRecord();
227 }
228
229 bool FaviconTabHelper::IsBookmarked(const GURL& url) {
230 return bookmark_model_ && bookmark_model_->IsBookmarked(url);
231 }
232
233 GURL FaviconTabHelper::GetActiveURL() {
234 NavigationEntry* entry = web_contents()->GetController().GetActiveEntry();
235 return entry ? entry->GetURL() : GURL();
236 }
237
238 base::string16 FaviconTabHelper::GetActiveTitle() {
239 NavigationEntry* entry = web_contents()->GetController().GetActiveEntry();
240 return entry ? entry->GetTitle() : base::string16();
241 }
242
243 bool FaviconTabHelper::GetActiveFaviconValidity() {
244 return GetFaviconStatus().valid;
245 }
246
247 void FaviconTabHelper::SetActiveFaviconValidity(bool valid) {
248 GetFaviconStatus().valid = valid;
249 }
250
251 GURL FaviconTabHelper::GetActiveFaviconURL() {
252 return GetFaviconStatus().url;
253 }
254
255 void FaviconTabHelper::SetActiveFaviconURL(const GURL& url) {
256 GetFaviconStatus().url = url;
257 }
258
259 gfx::Image FaviconTabHelper::GetActiveFaviconImage() {
260 return GetFaviconStatus().image;
261 }
262
263 void FaviconTabHelper::SetActiveFaviconImage(const gfx::Image& image) {
264 GetFaviconStatus().image = image;
265 }
266
267 void FaviconTabHelper::OnFaviconAvailable(const gfx::Image& image,
268 const GURL& icon_url,
269 bool is_active_favicon) {
270 if (is_active_favicon) {
271 bool icon_url_changed = GetActiveFaviconURL() != icon_url;
272 // No matter what happens, we need to mark the favicon as being set.
273 SetActiveFaviconValidity(true);
274 SetActiveFaviconURL(icon_url);
275
276 if (image.IsEmpty())
277 return;
278
279 SetActiveFaviconImage(image);
280 NotifyFaviconUpdated(icon_url_changed);
281 }
282 if (!image.IsEmpty()) {
283 FOR_EACH_OBSERVER(favicon::FaviconDriverObserver, observer_list_,
284 OnFaviconAvailable(image));
285 }
286 }
287
288 void FaviconTabHelper::NotifyFaviconUpdated(bool icon_url_changed) {
289 FOR_EACH_OBSERVER(favicon::FaviconDriverObserver, observer_list_,
290 OnFaviconUpdated(this, icon_url_changed));
291 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
292 }
293
294 void FaviconTabHelper::DidDownloadFavicon(
295 int id,
296 int http_status_code,
297 const GURL& image_url,
298 const std::vector<SkBitmap>& bitmaps,
299 const std::vector<gfx::Size>& original_bitmap_sizes) {
300 if (bitmaps.empty() && http_status_code == 404) {
301 DVLOG(1) << "Failed to Download Favicon:" << image_url;
302 if (favicon_service_)
303 favicon_service_->UnableToDownloadFavicon(image_url);
304 }
305
306 favicon_handler_->OnDidDownloadFavicon(id, image_url, bitmaps,
307 original_bitmap_sizes);
308 if (touch_icon_handler_.get()) {
309 touch_icon_handler_->OnDidDownloadFavicon(id, image_url, bitmaps,
310 original_bitmap_sizes);
311 }
312 if (large_icon_handler_.get()) {
313 large_icon_handler_->OnDidDownloadFavicon(id, image_url, bitmaps,
314 original_bitmap_sizes);
315 }
316 }
317
318 content::FaviconStatus& FaviconTabHelper::GetFaviconStatus() {
319 DCHECK(web_contents()->GetController().GetActiveEntry());
320 return web_contents()->GetController().GetActiveEntry()->GetFavicon();
321 }
322
323 void FaviconTabHelper::DidStartNavigationToPendingEntry(
324 const GURL& url,
325 NavigationController::ReloadType reload_type) {
326 if (reload_type == NavigationController::NO_RELOAD || IsOffTheRecord())
327 return;
328
329 bypass_cache_page_url_ = url;
330
331 if (favicon_service_) {
332 favicon_service_->SetFaviconOutOfDateForPage(url);
333 if (reload_type == NavigationController::RELOAD_IGNORING_CACHE)
334 favicon_service_->ClearUnableToDownloadFavicons();
335 }
336 }
337
338 void FaviconTabHelper::DidNavigateMainFrame(
339 const content::LoadCommittedDetails& details,
340 const content::FrameNavigateParams& params) {
341 favicon_urls_.clear();
342
343 // Wait till the user navigates to a new URL to start checking the cache
344 // again. The cache may be ignored for non-reload navigations (e.g.
345 // history.replace() in-page navigation). This is allowed to increase the
346 // likelihood that "reloading a page ignoring the cache" redownloads the
347 // favicon. In particular, a page may do an in-page navigation before
348 // FaviconHandler has the time to determine that the favicon needs to be
349 // redownloaded.
350 GURL url = details.entry->GetURL();
351 if (url != bypass_cache_page_url_)
352 bypass_cache_page_url_ = GURL();
353
354 // Get the favicon, either from history or request it from the net.
355 FetchFavicon(url);
356 }
357
358 void FaviconTabHelper::DidUpdateFaviconURL(
359 const std::vector<content::FaviconURL>& candidates) {
360 DCHECK(!candidates.empty());
361 favicon_urls_ = candidates;
362 std::vector<favicon::FaviconURL> favicon_urls =
363 favicon::FaviconURLsFromContentFaviconURLs(candidates);
364 favicon_handler_->OnUpdateFaviconURL(favicon_urls);
365 if (touch_icon_handler_.get())
366 touch_icon_handler_->OnUpdateFaviconURL(favicon_urls);
367 if (large_icon_handler_.get())
368 large_icon_handler_->OnUpdateFaviconURL(favicon_urls);
369 }
OLDNEW
« no previous file with comments | « chrome/browser/favicon/favicon_tab_helper.h ('k') | chrome/browser/favicon/favicon_tab_helper_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698