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.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 "net/url_request/url_request.h"
23 #include "ui/base/l10n/l10n_util.h"
24 #include "ui/base/layout.h"
25 #include "ui/base/resource/resource_bundle.h"
26 #include "ui/base/webui/web_ui_util.h"
27 #include "ui/resources/grit/ui_resources.h"
29 FaviconSource::IconRequest::IconRequest()
30 : size_in_dip(gfx::kFaviconSize
), device_scale_factor(1.0f
) {
33 FaviconSource::IconRequest::IconRequest(
34 const content::URLDataSource::GotDataCallback
& cb
,
41 device_scale_factor(scale
) {
44 FaviconSource::IconRequest::~IconRequest() {
47 FaviconSource::FaviconSource(Profile
* profile
, IconType type
)
48 : profile_(profile
->GetOriginalProfile()),
49 icon_types_(type
== FAVICON
? favicon_base::FAVICON
50 : favicon_base::TOUCH_PRECOMPOSED_ICON
|
51 favicon_base::TOUCH_ICON
|
52 favicon_base::FAVICON
) {}
54 FaviconSource::~FaviconSource() {
57 std::string
FaviconSource::GetSource() const {
58 return icon_types_
== favicon_base::FAVICON
? chrome::kChromeUIFaviconHost
59 : chrome::kChromeUITouchIconHost
;
62 void FaviconSource::StartDataRequest(
63 const std::string
& path
,
64 int render_process_id
,
66 const content::URLDataSource::GotDataCallback
& callback
) {
67 FaviconService
* favicon_service
= FaviconServiceFactory::GetForProfile(
68 profile_
, ServiceAccessType::EXPLICIT_ACCESS
);
69 if (!favicon_service
) {
70 SendDefaultResponse(callback
);
74 chrome::ParsedFaviconPath parsed
;
75 bool success
= chrome::ParseFaviconPath(path
, icon_types_
, &parsed
);
77 SendDefaultResponse(callback
);
82 int desired_size_in_pixel
=
83 std::ceil(parsed
.size_in_dip
* parsed
.device_scale_factor
);
85 if (parsed
.is_icon_url
) {
86 // TODO(michaelbai): Change GetRawFavicon to support combination of
88 favicon_service
->GetRawFavicon(
90 favicon_base::FAVICON
,
91 desired_size_in_pixel
,
93 &FaviconSource::OnFaviconDataAvailable
,
94 base::Unretained(this),
96 callback
, url
, parsed
.size_in_dip
, parsed
.device_scale_factor
)),
97 &cancelable_task_tracker_
);
99 // Intercept requests for prepopulated pages.
100 for (int i
= 0; i
< history::kPrepopulatedPagesCount
; i
++) {
102 l10n_util::GetStringUTF8(history::kPrepopulatedPages
[i
].url_id
)) {
103 ui::ScaleFactor resource_scale_factor
=
104 ui::GetSupportedScaleFactor(parsed
.device_scale_factor
);
106 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
107 history::kPrepopulatedPages
[i
].favicon_id
,
108 resource_scale_factor
));
113 favicon_service
->GetRawFaviconForPageURL(
116 desired_size_in_pixel
,
118 &FaviconSource::OnFaviconDataAvailable
,
119 base::Unretained(this),
121 callback
, url
, parsed
.size_in_dip
, parsed
.device_scale_factor
)),
122 &cancelable_task_tracker_
);
126 std::string
FaviconSource::GetMimeType(const std::string
&) const {
127 // We need to explicitly return a mime type, otherwise if the user tries to
128 // drag the image they get no extension.
132 bool FaviconSource::ShouldReplaceExistingSource() const {
133 // Leave the existing DataSource in place, otherwise we'll drop any pending
134 // requests on the floor.
138 bool FaviconSource::ShouldServiceRequest(const net::URLRequest
* request
) const {
139 if (request
->url().SchemeIs(chrome::kChromeSearchScheme
))
140 return InstantIOContext::ShouldServiceRequest(request
);
141 return URLDataSource::ShouldServiceRequest(request
);
144 bool FaviconSource::HandleMissingResource(const IconRequest
& request
) {
145 // If the favicon is not available, try to use the synced favicon.
146 ProfileSyncService
* sync_service
=
147 ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile_
);
148 browser_sync::OpenTabsUIDelegate
* open_tabs
= sync_service
?
149 sync_service
->GetOpenTabsUIDelegate() : NULL
;
151 scoped_refptr
<base::RefCountedMemory
> response
;
153 open_tabs
->GetSyncedFaviconForPageURL(request
.request_path
.spec(),
155 request
.callback
.Run(response
.get());
161 void FaviconSource::OnFaviconDataAvailable(
162 const IconRequest
& request
,
163 const favicon_base::FaviconRawBitmapResult
& bitmap_result
) {
164 if (bitmap_result
.is_valid()) {
165 // Forward the data along to the networking system.
166 request
.callback
.Run(bitmap_result
.bitmap_data
.get());
167 } else if (!HandleMissingResource(request
)) {
168 SendDefaultResponse(request
);
172 void FaviconSource::SendDefaultResponse(
173 const content::URLDataSource::GotDataCallback
& callback
) {
174 SendDefaultResponse(IconRequest(callback
, GURL(), 16, 1.0f
));
177 void FaviconSource::SendDefaultResponse(const IconRequest
& icon_request
) {
180 switch (icon_request
.size_in_dip
) {
182 favicon_index
= SIZE_64
;
183 resource_id
= IDR_DEFAULT_FAVICON_64
;
186 favicon_index
= SIZE_32
;
187 resource_id
= IDR_DEFAULT_FAVICON_32
;
190 favicon_index
= SIZE_16
;
191 resource_id
= IDR_DEFAULT_FAVICON
;
194 base::RefCountedMemory
* default_favicon
=
195 default_favicons_
[favicon_index
].get();
197 if (!default_favicon
) {
198 ui::ScaleFactor resource_scale_factor
=
199 ui::GetSupportedScaleFactor(icon_request
.device_scale_factor
);
201 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale(
202 resource_id
, resource_scale_factor
);
203 default_favicons_
[favicon_index
] = default_favicon
;
206 icon_request
.callback
.Run(default_favicon
);