Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / favicon / favicon_tab_helper.cc
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.
4
5 #include "chrome/browser/favicon/favicon_tab_helper.h"
6
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"
34
35 using content::FaviconStatus;
36 using content::NavigationController;
37 using content::NavigationEntry;
38 using content::WebContents;
39
40 DEFINE_WEB_CONTENTS_USER_DATA_KEY(FaviconTabHelper);
41
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));
56 }
57
58 FaviconTabHelper::~FaviconTabHelper() {
59 }
60
61 void FaviconTabHelper::FetchFavicon(const GURL& url) {
62   favicon_handler_->FetchFavicon(url);
63   if (touch_icon_handler_.get())
64     touch_icon_handler_->FetchFavicon(url);
65 }
66
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;
74
75   entry = controller.GetLastCommittedEntry();
76   if (entry)
77     return entry->GetFavicon().image;
78   return gfx::Image();
79 }
80
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;
86
87   entry = controller.GetLastCommittedEntry();
88   if (entry)
89     return entry->GetFavicon().valid;
90
91   return false;
92 }
93
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;
99
100   GURL url = web_contents()->GetURL();
101   if (url.SchemeIs(content::kChromeUIScheme) &&
102       url.host() == chrome::kChromeUINewTabHost) {
103     return false;
104   }
105
106   // No favicon on Instant New Tab Pages.
107   if (chrome::IsInstantNTP(web_contents()))
108     return false;
109
110   return true;
111 }
112
113 void FaviconTabHelper::SaveFavicon() {
114   NavigationEntry* entry = web_contents()->GetController().GetActiveEntry();
115   if (!entry || entry->GetURL().is_empty())
116     return;
117
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());
125
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;
134   }
135   service->SetFavicons(
136       entry->GetURL(), favicon.url, favicon_base::FAVICON, favicon.image);
137 }
138
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;
145   }
146
147   return web_contents()->DownloadImage(
148       url,
149       true,
150       max_image_size,
151       base::Bind(&FaviconTabHelper::DidDownloadFavicon,base::Unretained(this)));
152 }
153
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);
160 }
161
162 bool FaviconTabHelper::IsOffTheRecord() {
163   DCHECK(web_contents());
164   return web_contents()->GetBrowserContext()->IsOffTheRecord();
165 }
166
167 const gfx::Image FaviconTabHelper::GetActiveFaviconImage() {
168   return GetFaviconStatus().image;
169 }
170
171 const GURL FaviconTabHelper::GetActiveFaviconURL() {
172   return GetFaviconStatus().url;
173 }
174
175 bool FaviconTabHelper::GetActiveFaviconValidity() {
176   return GetFaviconStatus().valid;
177 }
178
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();
184 }
185
186 void FaviconTabHelper::SetActiveFaviconImage(gfx::Image image) {
187   GetFaviconStatus().image = image;
188 }
189
190 void FaviconTabHelper::SetActiveFaviconURL(GURL url) {
191   GetFaviconStatus().url = url;
192 }
193
194 void FaviconTabHelper::SetActiveFaviconValidity(bool validity) {
195   GetFaviconStatus().valid = validity;
196 }
197
198 content::FaviconStatus& FaviconTabHelper::GetFaviconStatus() {
199   DCHECK(web_contents()->GetController().GetActiveEntry());
200   return web_contents()->GetController().GetActiveEntry()->GetFavicon();
201 }
202
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();
214     }
215   }
216 }
217
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());
224 }
225
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;
240   }
241   NOTREACHED();
242   return favicon_base::INVALID_ICON;
243 }
244
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));
256   }
257   favicon_handler_->OnUpdateFaviconURL(favicon_urls);
258   if (touch_icon_handler_.get())
259     touch_icon_handler_->OnUpdateFaviconURL(favicon_urls);
260 }
261
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) {
268
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);
275   }
276
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);
282   }
283 }