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/open_tabs_ui_delegate.h"
17 #include "chrome/browser/sync/profile_sync_service.h"
18 #include "chrome/browser/sync/profile_sync_service_factory.h"
19 #include "chrome/common/favicon/favicon_url_parser.h"
20 #include "chrome/common/url_constants.h"
21 #include "chrome/grit/locale_settings.h"
22 #include "components/history/core/browser/top_sites.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 FaviconService
* favicon_service
= FaviconServiceFactory::GetForProfile(
69 profile_
, ServiceAccessType::EXPLICIT_ACCESS
);
70 if (!favicon_service
) {
71 SendDefaultResponse(callback
);
75 chrome::ParsedFaviconPath parsed
;
76 bool success
= chrome::ParseFaviconPath(path
, icon_types_
, &parsed
);
78 SendDefaultResponse(callback
);
83 int desired_size_in_pixel
=
84 std::ceil(parsed
.size_in_dip
* parsed
.device_scale_factor
);
86 if (parsed
.is_icon_url
) {
87 // TODO(michaelbai): Change GetRawFavicon to support combination of
89 favicon_service
->GetRawFavicon(
91 favicon_base::FAVICON
,
92 desired_size_in_pixel
,
94 &FaviconSource::OnFaviconDataAvailable
,
95 base::Unretained(this),
97 callback
, url
, parsed
.size_in_dip
, parsed
.device_scale_factor
)),
98 &cancelable_task_tracker_
);
100 // Intercept requests for prepopulated pages if TopSites exists.
101 scoped_refptr
<history::TopSites
> top_sites
=
102 TopSitesFactory::GetForProfile(profile_
);
104 for (const auto& prepopulated_page
: top_sites
->GetPrepopulatedPages()) {
105 if (url
== prepopulated_page
.most_visited
.url
) {
106 ui::ScaleFactor resource_scale_factor
=
107 ui::GetSupportedScaleFactor(parsed
.device_scale_factor
);
109 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
110 prepopulated_page
.favicon_id
, resource_scale_factor
));
116 favicon_service
->GetRawFaviconForPageURL(
119 desired_size_in_pixel
,
121 &FaviconSource::OnFaviconDataAvailable
,
122 base::Unretained(this),
124 callback
, url
, parsed
.size_in_dip
, parsed
.device_scale_factor
)),
125 &cancelable_task_tracker_
);
129 std::string
FaviconSource::GetMimeType(const std::string
&) const {
130 // We need to explicitly return a mime type, otherwise if the user tries to
131 // drag the image they get no extension.
135 bool FaviconSource::ShouldReplaceExistingSource() const {
136 // Leave the existing DataSource in place, otherwise we'll drop any pending
137 // requests on the floor.
141 bool FaviconSource::ShouldServiceRequest(const net::URLRequest
* request
) const {
142 if (request
->url().SchemeIs(chrome::kChromeSearchScheme
))
143 return InstantIOContext::ShouldServiceRequest(request
);
144 return URLDataSource::ShouldServiceRequest(request
);
147 bool FaviconSource::HandleMissingResource(const IconRequest
& request
) {
148 // If the favicon is not available, try to use the synced favicon.
149 ProfileSyncService
* sync_service
=
150 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_
);
151 browser_sync::OpenTabsUIDelegate
* open_tabs
= sync_service
?
152 sync_service
->GetOpenTabsUIDelegate() : NULL
;
154 scoped_refptr
<base::RefCountedMemory
> response
;
156 open_tabs
->GetSyncedFaviconForPageURL(request
.request_path
.spec(),
158 request
.callback
.Run(response
.get());
164 void FaviconSource::OnFaviconDataAvailable(
165 const IconRequest
& request
,
166 const favicon_base::FaviconRawBitmapResult
& bitmap_result
) {
167 if (bitmap_result
.is_valid()) {
168 // Forward the data along to the networking system.
169 request
.callback
.Run(bitmap_result
.bitmap_data
.get());
170 } else if (!HandleMissingResource(request
)) {
171 SendDefaultResponse(request
);
175 void FaviconSource::SendDefaultResponse(
176 const content::URLDataSource::GotDataCallback
& callback
) {
177 SendDefaultResponse(IconRequest(callback
, GURL(), 16, 1.0f
));
180 void FaviconSource::SendDefaultResponse(const IconRequest
& icon_request
) {
183 switch (icon_request
.size_in_dip
) {
185 favicon_index
= SIZE_64
;
186 resource_id
= IDR_DEFAULT_FAVICON_64
;
189 favicon_index
= SIZE_32
;
190 resource_id
= IDR_DEFAULT_FAVICON_32
;
193 favicon_index
= SIZE_16
;
194 resource_id
= IDR_DEFAULT_FAVICON
;
197 base::RefCountedMemory
* default_favicon
=
198 default_favicons_
[favicon_index
].get();
200 if (!default_favicon
) {
201 ui::ScaleFactor resource_scale_factor
=
202 ui::GetSupportedScaleFactor(icon_request
.device_scale_factor
);
204 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
205 resource_id
, resource_scale_factor
);
206 default_favicons_
[favicon_index
] = default_favicon
;
209 icon_request
.callback
.Run(default_favicon
);