1 // Copyright 2015 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 "components/favicon/content/content_favicon_driver.h"
8 #include "components/favicon/content/favicon_url_util.h"
9 #include "components/favicon/core/favicon_service.h"
10 #include "components/favicon/core/favicon_url.h"
11 #include "components/history/core/browser/history_service.h"
12 #include "content/public/browser/browser_context.h"
13 #include "content/public/browser/favicon_status.h"
14 #include "content/public/browser/navigation_controller.h"
15 #include "content/public/browser/navigation_details.h"
16 #include "content/public/browser/navigation_entry.h"
17 #include "content/public/common/favicon_url.h"
18 #include "ui/gfx/image/image.h"
20 DEFINE_WEB_CONTENTS_USER_DATA_KEY(favicon::ContentFaviconDriver
);
25 void ContentFaviconDriver::CreateForWebContents(
26 content::WebContents
* web_contents
,
27 FaviconService
* favicon_service
,
28 history::HistoryService
* history_service
,
29 bookmarks::BookmarkModel
* bookmark_model
) {
30 if (FromWebContents(web_contents
))
33 web_contents
->SetUserData(
34 UserDataKey(), new ContentFaviconDriver(web_contents
, favicon_service
,
35 history_service
, bookmark_model
));
38 void ContentFaviconDriver::SaveFavicon() {
39 content::NavigationEntry
* entry
=
40 web_contents()->GetController().GetLastCommittedEntry();
44 // Make sure the page is in history, otherwise adding the favicon does
46 if (!history_service())
48 GURL page_url
= entry
->GetURL();
49 history_service()->AddPageNoVisitForBookmark(page_url
, entry
->GetTitle());
51 const content::FaviconStatus
& favicon_status
= entry
->GetFavicon();
52 if (!favicon_service() || !favicon_status
.valid
||
53 favicon_status
.url
.is_empty() || favicon_status
.image
.IsEmpty()) {
57 favicon_service()->SetFavicons(page_url
, favicon_status
.url
,
58 favicon_base::FAVICON
, favicon_status
.image
);
61 gfx::Image
ContentFaviconDriver::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 content::NavigationController
& controller
=
65 web_contents()->GetController();
66 content::NavigationEntry
* entry
= controller
.GetTransientEntry();
68 return entry
->GetFavicon().image
;
70 entry
= controller
.GetLastCommittedEntry();
72 return entry
->GetFavicon().image
;
76 bool ContentFaviconDriver::FaviconIsValid() const {
77 const content::NavigationController
& controller
=
78 web_contents()->GetController();
79 content::NavigationEntry
* entry
= controller
.GetTransientEntry();
81 return entry
->GetFavicon().valid
;
83 entry
= controller
.GetLastCommittedEntry();
85 return entry
->GetFavicon().valid
;
90 int ContentFaviconDriver::StartDownload(const GURL
& url
, int max_image_size
) {
91 if (WasUnableToDownloadFavicon(url
)) {
92 DVLOG(1) << "Skip Failed FavIcon: " << url
;
96 bool bypass_cache
= (bypass_cache_page_url_
== GetActiveURL());
97 bypass_cache_page_url_
= GURL();
99 return web_contents()->DownloadImage(
100 url
, true, max_image_size
, bypass_cache
,
101 base::Bind(&FaviconDriverImpl::DidDownloadFavicon
,
102 base::Unretained(this)));
105 bool ContentFaviconDriver::IsOffTheRecord() {
106 DCHECK(web_contents());
107 return web_contents()->GetBrowserContext()->IsOffTheRecord();
110 GURL
ContentFaviconDriver::GetActiveURL() {
111 content::NavigationEntry
* entry
=
112 web_contents()->GetController().GetLastCommittedEntry();
113 return entry
? entry
->GetURL() : GURL();
116 bool ContentFaviconDriver::GetActiveFaviconValidity() {
117 return GetFaviconStatus().valid
;
120 void ContentFaviconDriver::SetActiveFaviconValidity(bool valid
) {
121 GetFaviconStatus().valid
= valid
;
124 GURL
ContentFaviconDriver::GetActiveFaviconURL() {
125 return GetFaviconStatus().url
;
128 void ContentFaviconDriver::SetActiveFaviconURL(const GURL
& url
) {
129 GetFaviconStatus().url
= url
;
132 void ContentFaviconDriver::SetActiveFaviconImage(const gfx::Image
& image
) {
133 GetFaviconStatus().image
= image
;
136 content::FaviconStatus
& ContentFaviconDriver::GetFaviconStatus() {
137 DCHECK(web_contents()->GetController().GetLastCommittedEntry());
138 return web_contents()->GetController().GetLastCommittedEntry()->GetFavicon();
141 ContentFaviconDriver::ContentFaviconDriver(
142 content::WebContents
* web_contents
,
143 FaviconService
* favicon_service
,
144 history::HistoryService
* history_service
,
145 bookmarks::BookmarkModel
* bookmark_model
)
146 : content::WebContentsObserver(web_contents
),
147 FaviconDriverImpl(favicon_service
, history_service
, bookmark_model
) {
150 ContentFaviconDriver::~ContentFaviconDriver() {
153 void ContentFaviconDriver::NotifyFaviconUpdated(bool icon_url_changed
) {
154 FaviconDriverImpl::NotifyFaviconUpdated(icon_url_changed
);
155 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB
);
158 void ContentFaviconDriver::DidUpdateFaviconURL(
159 const std::vector
<content::FaviconURL
>& candidates
) {
160 DCHECK(!candidates
.empty());
162 // Ignore the update if there is no last committed navigation entry. This can
163 // occur when loading an initially blank page.
164 if (!web_contents()->GetController().GetLastCommittedEntry())
167 favicon_urls_
= candidates
;
168 OnUpdateFaviconURL(FaviconURLsFromContentFaviconURLs(candidates
));
171 void ContentFaviconDriver::DidStartNavigationToPendingEntry(
173 content::NavigationController::ReloadType reload_type
) {
174 if (reload_type
== content::NavigationController::NO_RELOAD
||
178 bypass_cache_page_url_
= url
;
179 SetFaviconOutOfDateForPage(
180 url
, reload_type
== content::NavigationController::RELOAD_IGNORING_CACHE
);
183 void ContentFaviconDriver::DidNavigateMainFrame(
184 const content::LoadCommittedDetails
& details
,
185 const content::FrameNavigateParams
& params
) {
186 favicon_urls_
.clear();
188 // Wait till the user navigates to a new URL to start checking the cache
189 // again. The cache may be ignored for non-reload navigations (e.g.
190 // history.replace() in-page navigation). This is allowed to increase the
191 // likelihood that "reloading a page ignoring the cache" redownloads the
192 // favicon. In particular, a page may do an in-page navigation before
193 // FaviconHandler has the time to determine that the favicon needs to be
195 GURL url
= details
.entry
->GetURL();
196 if (url
!= bypass_cache_page_url_
)
197 bypass_cache_page_url_
= GURL();
199 // Get the favicon, either from history or request it from the net.
203 } // namespace favicon