Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / favicon / content / content_favicon_driver.cc
blobc4aa894affd32a4b92cf54a7ed393a4b8fac2b11
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"
7 #include "base/bind.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);
22 namespace favicon {
24 // static
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))
31 return;
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();
41 if (!entry)
42 return;
44 // Make sure the page is in history, otherwise adding the favicon does
45 // nothing.
46 if (!history_service())
47 return;
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()) {
54 return;
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();
67 if (entry)
68 return entry->GetFavicon().image;
70 entry = controller.GetLastCommittedEntry();
71 if (entry)
72 return entry->GetFavicon().image;
73 return gfx::Image();
76 bool ContentFaviconDriver::FaviconIsValid() const {
77 const content::NavigationController& controller =
78 web_contents()->GetController();
79 content::NavigationEntry* entry = controller.GetTransientEntry();
80 if (entry)
81 return entry->GetFavicon().valid;
83 entry = controller.GetLastCommittedEntry();
84 if (entry)
85 return entry->GetFavicon().valid;
87 return false;
90 int ContentFaviconDriver::StartDownload(const GURL& url, int max_image_size) {
91 if (WasUnableToDownloadFavicon(url)) {
92 DVLOG(1) << "Skip Failed FavIcon: " << url;
93 return 0;
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())
165 return;
167 favicon_urls_ = candidates;
168 OnUpdateFaviconURL(FaviconURLsFromContentFaviconURLs(candidates));
171 void ContentFaviconDriver::DidStartNavigationToPendingEntry(
172 const GURL& url,
173 content::NavigationController::ReloadType reload_type) {
174 if (reload_type == content::NavigationController::NO_RELOAD ||
175 IsOffTheRecord())
176 return;
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
194 // redownloaded.
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.
200 FetchFavicon(url);
203 } // namespace favicon