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/ui/webui/favicon_source.h"
10 #include "base/bind_helpers.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "chrome/browser/favicon/favicon_service_factory.h"
13 #include "chrome/browser/history/top_sites_factory.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/search/instant_io_context.h"
16 #include "chrome/browser/sync/profile_sync_service.h"
17 #include "chrome/browser/sync/profile_sync_service_factory.h"
18 #include "chrome/common/url_constants.h"
19 #include "chrome/grit/locale_settings.h"
20 #include "components/favicon_base/favicon_url_parser.h"
21 #include "components/history/core/browser/top_sites.h"
22 #include "components/sync_driver/open_tabs_ui_delegate.h"
23 #include "net/url_request/url_request.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/base/layout.h"
26 #include "ui/base/resource/resource_bundle.h"
27 #include "ui/base/webui/web_ui_util.h"
28 #include "ui/resources/grit/ui_resources.h"
30 FaviconSource::IconRequest::IconRequest()
31 : size_in_dip(gfx::kFaviconSize
), device_scale_factor(1.0f
) {
34 FaviconSource::IconRequest::IconRequest(
35 const content::URLDataSource::GotDataCallback
& cb
,
42 device_scale_factor(scale
) {
45 FaviconSource::IconRequest::~IconRequest() {
48 FaviconSource::FaviconSource(Profile
* profile
, IconType type
)
49 : profile_(profile
->GetOriginalProfile()),
50 icon_types_(type
== FAVICON
? favicon_base::FAVICON
51 : favicon_base::TOUCH_PRECOMPOSED_ICON
|
52 favicon_base::TOUCH_ICON
|
53 favicon_base::FAVICON
) {}
55 FaviconSource::~FaviconSource() {
58 std::string
FaviconSource::GetSource() const {
59 return icon_types_
== favicon_base::FAVICON
? chrome::kChromeUIFaviconHost
60 : chrome::kChromeUITouchIconHost
;
63 void FaviconSource::StartDataRequest(
64 const std::string
& path
,
65 int render_process_id
,
67 const content::URLDataSource::GotDataCallback
& callback
) {
68 favicon::FaviconService
* favicon_service
=
69 FaviconServiceFactory::GetForProfile(profile_
,
70 ServiceAccessType::EXPLICIT_ACCESS
);
71 if (!favicon_service
) {
72 SendDefaultResponse(callback
);
76 chrome::ParsedFaviconPath parsed
;
77 bool success
= chrome::ParseFaviconPath(path
, icon_types_
, &parsed
);
79 SendDefaultResponse(callback
);
84 int desired_size_in_pixel
=
85 std::ceil(parsed
.size_in_dip
* parsed
.device_scale_factor
);
87 if (parsed
.is_icon_url
) {
88 // TODO(michaelbai): Change GetRawFavicon to support combination of
90 favicon_service
->GetRawFavicon(
92 favicon_base::FAVICON
,
93 desired_size_in_pixel
,
95 &FaviconSource::OnFaviconDataAvailable
,
96 base::Unretained(this),
98 callback
, url
, parsed
.size_in_dip
, parsed
.device_scale_factor
)),
99 &cancelable_task_tracker_
);
101 // Intercept requests for prepopulated pages if TopSites exists.
102 scoped_refptr
<history::TopSites
> top_sites
=
103 TopSitesFactory::GetForProfile(profile_
);
105 for (const auto& prepopulated_page
: top_sites
->GetPrepopulatedPages()) {
106 if (url
== prepopulated_page
.most_visited
.url
) {
107 ui::ScaleFactor resource_scale_factor
=
108 ui::GetSupportedScaleFactor(parsed
.device_scale_factor
);
110 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
111 prepopulated_page
.favicon_id
, resource_scale_factor
));
117 favicon_service
->GetRawFaviconForPageURL(
120 desired_size_in_pixel
,
122 &FaviconSource::OnFaviconDataAvailable
,
123 base::Unretained(this),
125 callback
, url
, parsed
.size_in_dip
, parsed
.device_scale_factor
)),
126 &cancelable_task_tracker_
);
130 std::string
FaviconSource::GetMimeType(const std::string
&) const {
131 // We need to explicitly return a mime type, otherwise if the user tries to
132 // drag the image they get no extension.
136 bool FaviconSource::ShouldReplaceExistingSource() const {
137 // Leave the existing DataSource in place, otherwise we'll drop any pending
138 // requests on the floor.
142 bool FaviconSource::ShouldServiceRequest(const net::URLRequest
* request
) const {
143 if (request
->url().SchemeIs(chrome::kChromeSearchScheme
))
144 return InstantIOContext::ShouldServiceRequest(request
);
145 return URLDataSource::ShouldServiceRequest(request
);
148 bool FaviconSource::HandleMissingResource(const IconRequest
& request
) {
149 // If the favicon is not available, try to use the synced favicon.
150 ProfileSyncService
* sync_service
=
151 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_
);
152 sync_driver::OpenTabsUIDelegate
* open_tabs
=
153 sync_service
? sync_service
->GetOpenTabsUIDelegate() : nullptr;
155 scoped_refptr
<base::RefCountedMemory
> response
;
157 open_tabs
->GetSyncedFaviconForPageURL(request
.request_path
.spec(),
159 request
.callback
.Run(response
.get());
165 void FaviconSource::OnFaviconDataAvailable(
166 const IconRequest
& request
,
167 const favicon_base::FaviconRawBitmapResult
& bitmap_result
) {
168 if (bitmap_result
.is_valid()) {
169 // Forward the data along to the networking system.
170 request
.callback
.Run(bitmap_result
.bitmap_data
.get());
171 } else if (!HandleMissingResource(request
)) {
172 SendDefaultResponse(request
);
176 void FaviconSource::SendDefaultResponse(
177 const content::URLDataSource::GotDataCallback
& callback
) {
178 SendDefaultResponse(IconRequest(callback
, GURL(), 16, 1.0f
));
181 void FaviconSource::SendDefaultResponse(const IconRequest
& icon_request
) {
184 switch (icon_request
.size_in_dip
) {
186 favicon_index
= SIZE_64
;
187 resource_id
= IDR_DEFAULT_FAVICON_64
;
190 favicon_index
= SIZE_32
;
191 resource_id
= IDR_DEFAULT_FAVICON_32
;
194 favicon_index
= SIZE_16
;
195 resource_id
= IDR_DEFAULT_FAVICON
;
198 base::RefCountedMemory
* default_favicon
=
199 default_favicons_
[favicon_index
].get();
201 if (!default_favicon
) {
202 ui::ScaleFactor resource_scale_factor
=
203 ui::GetSupportedScaleFactor(icon_request
.device_scale_factor
);
205 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
206 resource_id
, resource_scale_factor
);
207 default_favicons_
[favicon_index
] = default_favicon
;
210 icon_request
.callback
.Run(default_favicon
);