| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/webui/favicon_source.h" | 5 #include "chrome/browser/ui/webui/favicon_source.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/string_number_conversions.h" |
| 9 #include "chrome/browser/favicon/favicon_service_factory.h" | 10 #include "chrome/browser/favicon/favicon_service_factory.h" |
| 10 #include "chrome/browser/history/top_sites.h" | 11 #include "chrome/browser/history/top_sites.h" |
| 11 #include "chrome/browser/profiles/profile.h" | 12 #include "chrome/browser/profiles/profile.h" |
| 12 #include "chrome/browser/ui/webui/web_ui_util.h" | 13 #include "chrome/browser/ui/webui/web_ui_util.h" |
| 13 #include "chrome/common/url_constants.h" | 14 #include "chrome/common/url_constants.h" |
| 14 #include "grit/locale_settings.h" | 15 #include "grit/locale_settings.h" |
| 15 #include "grit/ui_resources.h" | 16 #include "grit/ui_resources.h" |
| 16 #include "ui/base/l10n/l10n_util.h" | 17 #include "ui/base/l10n/l10n_util.h" |
| 17 #include "ui/base/layout.h" | 18 #include "ui/base/layout.h" |
| 18 #include "ui/base/resource/resource_bundle.h" | 19 #include "ui/base/resource/resource_bundle.h" |
| 19 | 20 |
| 21 namespace { |
| 22 |
| 23 // Parameters which can be used in chrome://favicon path. See .h file for a |
| 24 // description of what each does. |
| 25 const char kSizeParameter[] = "size/"; |
| 26 const char kIconURLParameter[] = "iconurl/"; |
| 27 const char kOriginParameter[] = "origin/"; |
| 28 |
| 29 // Returns true if |search| is a substring of |path| which starts at |
| 30 // |start_index|. |
| 31 bool HasSubstringAt(const std::string& path, |
| 32 size_t start_index, |
| 33 const std::string& search) { |
| 34 if (search.empty()) |
| 35 return false; |
| 36 |
| 37 if (start_index + search.size() >= path.size()) |
| 38 return false; |
| 39 |
| 40 return (path.compare(start_index, search.size(), search) == 0); |
| 41 } |
| 42 |
| 43 } // namespace |
| 44 |
| 20 FaviconSource::IconRequest::IconRequest() | 45 FaviconSource::IconRequest::IconRequest() |
| 21 : size_in_dip(gfx::kFaviconSize), | 46 : size_in_dip(gfx::kFaviconSize), |
| 22 scale_factor(ui::SCALE_FACTOR_NONE) { | 47 scale_factor(ui::SCALE_FACTOR_NONE) { |
| 23 } | 48 } |
| 24 | 49 |
| 25 FaviconSource::IconRequest::IconRequest( | 50 FaviconSource::IconRequest::IconRequest( |
| 26 const content::URLDataSource::GotDataCallback& cb, | 51 const content::URLDataSource::GotDataCallback& cb, |
| 27 const std::string& path, | 52 const std::string& path, |
| 28 int size, | 53 int size, |
| 29 ui::ScaleFactor scale) | 54 ui::ScaleFactor scale) |
| (...skipping 21 matching lines...) Expand all Loading... |
| 51 chrome::kChromeUIFaviconHost : chrome::kChromeUITouchIconHost; | 76 chrome::kChromeUIFaviconHost : chrome::kChromeUITouchIconHost; |
| 52 } | 77 } |
| 53 | 78 |
| 54 void FaviconSource::StartDataRequest( | 79 void FaviconSource::StartDataRequest( |
| 55 const std::string& path, | 80 const std::string& path, |
| 56 bool is_incognito, | 81 bool is_incognito, |
| 57 const content::URLDataSource::GotDataCallback& callback) { | 82 const content::URLDataSource::GotDataCallback& callback) { |
| 58 FaviconService* favicon_service = | 83 FaviconService* favicon_service = |
| 59 FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); | 84 FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); |
| 60 if (!favicon_service || path.empty()) { | 85 if (!favicon_service || path.empty()) { |
| 61 SendDefaultResponse(IconRequest(callback, | 86 SendDefaultResponse(callback); |
| 62 "", | |
| 63 16, | |
| 64 ui::SCALE_FACTOR_100P)); | |
| 65 return; | 87 return; |
| 66 } | 88 } |
| 67 | 89 |
| 68 int size_in_dip = gfx::kFaviconSize; | 90 DCHECK_EQ(16, gfx::kFaviconSize); |
| 91 int size_in_dip = 16; |
| 69 ui::ScaleFactor scale_factor = ui::SCALE_FACTOR_100P; | 92 ui::ScaleFactor scale_factor = ui::SCALE_FACTOR_100P; |
| 70 | 93 |
| 71 if (path.size() > 8 && | 94 size_t parsed_index = 0; |
| 72 (path.substr(0, 8) == "iconurl/" || path.substr(0, 8) == "iconurl@")) { | 95 if (HasSubstringAt(path, parsed_index, kSizeParameter)) { |
| 73 size_t prefix_length = 8; | 96 parsed_index += strlen(kSizeParameter); |
| 74 // Optional scale factor appended to iconurl, which may be @1x or @2x. | 97 |
| 75 if (path.at(7) == '@') { | 98 size_t scale_delimiter = path.find("@", parsed_index); |
| 76 size_t slash = path.find("/"); | 99 if (scale_delimiter == std::string::npos) { |
| 77 std::string scale_str = path.substr(8, slash - 8); | 100 SendDefaultResponse(callback); |
| 78 web_ui_util::ParseScaleFactor(scale_str, &scale_factor); | 101 return; |
| 79 prefix_length = slash + 1; | |
| 80 } | 102 } |
| 103 |
| 104 std::string size = path.substr(parsed_index, |
| 105 scale_delimiter - parsed_index); |
| 106 if (!base::StringToInt(size, &size_in_dip)) { |
| 107 SendDefaultResponse(callback); |
| 108 return; |
| 109 } |
| 110 |
| 111 if (size_in_dip != 64 && size_in_dip != 32) { |
| 112 // Only 64x64, 32x32 and 16x16 icons are supported. |
| 113 size_in_dip = 16; |
| 114 } |
| 115 |
| 116 size_t slash = path.find("/", scale_delimiter); |
| 117 if (slash == std::string::npos) { |
| 118 SendDefaultResponse(callback); |
| 119 return; |
| 120 } |
| 121 |
| 122 std::string scale_str = path.substr(scale_delimiter + 1, |
| 123 slash - scale_delimiter - 1); |
| 124 web_ui_util::ParseScaleFactor(scale_str, &scale_factor); |
| 125 |
| 126 if (scale_factor != ui::SCALE_FACTOR_100P && size_in_dip != 16) { |
| 127 SendDefaultResponse(callback); |
| 128 return; |
| 129 } |
| 130 |
| 131 parsed_index = slash + 1; |
| 132 } |
| 133 |
| 134 if (HasSubstringAt(path, parsed_index, kIconURLParameter)) { |
| 135 parsed_index += strlen(kIconURLParameter); |
| 81 // TODO(michaelbai): Change GetRawFavicon to support combination of | 136 // TODO(michaelbai): Change GetRawFavicon to support combination of |
| 82 // IconType. | 137 // IconType. |
| 83 favicon_service->GetRawFavicon( | 138 favicon_service->GetRawFavicon( |
| 84 GURL(path.substr(prefix_length)), | 139 GURL(path.substr(parsed_index)), |
| 85 history::FAVICON, | 140 history::FAVICON, |
| 86 size_in_dip, | 141 size_in_dip, |
| 87 scale_factor, | 142 scale_factor, |
| 88 base::Bind(&FaviconSource::OnFaviconDataAvailable, | 143 base::Bind(&FaviconSource::OnFaviconDataAvailable, |
| 89 base::Unretained(this), | 144 base::Unretained(this), |
| 90 IconRequest(callback, | 145 IconRequest(callback, |
| 91 path.substr(prefix_length), | 146 path.substr(parsed_index), |
| 92 size_in_dip, | 147 size_in_dip, |
| 93 scale_factor)), | 148 scale_factor)), |
| 94 &cancelable_task_tracker_); | 149 &cancelable_task_tracker_); |
| 95 } else { | 150 } else { |
| 96 GURL url; | 151 std::string url; |
| 97 if (path.size() > 5 && path.substr(0, 5) == "size/") { | 152 |
| 98 size_t slash = path.find("/", 5); | 153 // URL requests prefixed with "origin/" are converted to a form with an |
| 99 size_t scale_delimiter = path.find("@", 5); | 154 // empty path and a valid scheme. (e.g., example.com --> |
| 100 std::string size = path.substr(5, slash - 5); | 155 // http://example.com/ or http://example.com/a --> http://example.com/) |
| 101 size_in_dip = atoi(size.c_str()); | 156 if (HasSubstringAt(path, parsed_index, kOriginParameter)) { |
| 102 if (size_in_dip != 64 && size_in_dip != 32 && size_in_dip != 16) { | 157 parsed_index += strlen(kOriginParameter); |
| 103 // Only 64x64, 32x32 and 16x16 icons are supported. | 158 url = path.substr(parsed_index); |
| 104 size_in_dip = 16; | 159 |
| 105 } | 160 // If the URL does not specify a scheme (e.g., example.com instead of |
| 106 // Optional scale factor. | 161 // http://example.com), add "http://" as a default. |
| 107 if (scale_delimiter != std::string::npos && scale_delimiter < slash) { | 162 if (!GURL(url).has_scheme()) |
| 108 DCHECK(size_in_dip == 16); | 163 url = "http://" + url; |
| 109 std::string scale_str = path.substr(scale_delimiter + 1, | 164 |
| 110 slash - scale_delimiter - 1); | 165 // Strip the path beyond the top-level domain. |
| 111 web_ui_util::ParseScaleFactor(scale_str, &scale_factor); | 166 url = GURL(url).GetOrigin().spec(); |
| 112 } | |
| 113 url = GURL(path.substr(slash + 1)); | |
| 114 } else { | 167 } else { |
| 115 // URL requests prefixed with "origin/" are converted to a form with an | 168 url = path.substr(parsed_index); |
| 116 // empty path and a valid scheme. (e.g., example.com --> | |
| 117 // http://example.com/ or http://example.com/a --> http://example.com/) | |
| 118 if (path.size() > 7 && path.substr(0, 7) == "origin/") { | |
| 119 std::string originalUrl = path.substr(7); | |
| 120 | |
| 121 // If the original URL does not specify a scheme (e.g., example.com | |
| 122 // instead of http://example.com), add "http://" as a default. | |
| 123 if (!GURL(originalUrl).has_scheme()) | |
| 124 originalUrl = "http://" + originalUrl; | |
| 125 | |
| 126 // Strip the path beyond the top-level domain. | |
| 127 url = GURL(originalUrl).GetOrigin(); | |
| 128 } else { | |
| 129 url = GURL(path); | |
| 130 } | |
| 131 } | 169 } |
| 132 | 170 |
| 133 // Intercept requests for prepopulated pages. | 171 // Intercept requests for prepopulated pages. |
| 134 for (size_t i = 0; i < arraysize(history::kPrepopulatedPages); i++) { | 172 for (size_t i = 0; i < arraysize(history::kPrepopulatedPages); i++) { |
| 135 if (url.spec() == | 173 if (url == |
| 136 l10n_util::GetStringUTF8(history::kPrepopulatedPages[i].url_id)) { | 174 l10n_util::GetStringUTF8(history::kPrepopulatedPages[i].url_id)) { |
| 137 callback.Run( | 175 callback.Run( |
| 138 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale( | 176 ResourceBundle::GetSharedInstance().LoadDataResourceBytesForScale( |
| 139 history::kPrepopulatedPages[i].favicon_id, | 177 history::kPrepopulatedPages[i].favicon_id, |
| 140 scale_factor)); | 178 scale_factor)); |
| 141 return; | 179 return; |
| 142 } | 180 } |
| 143 } | 181 } |
| 144 | 182 |
| 145 favicon_service->GetRawFaviconForURL( | 183 favicon_service->GetRawFaviconForURL( |
| 146 FaviconService::FaviconForURLParams( | 184 FaviconService::FaviconForURLParams( |
| 147 profile_, url, icon_types_, size_in_dip), | 185 profile_, GURL(url), icon_types_, size_in_dip), |
| 148 scale_factor, | 186 scale_factor, |
| 149 base::Bind(&FaviconSource::OnFaviconDataAvailable, | 187 base::Bind(&FaviconSource::OnFaviconDataAvailable, |
| 150 base::Unretained(this), | 188 base::Unretained(this), |
| 151 IconRequest(callback, | 189 IconRequest(callback, |
| 152 url.spec(), | 190 url, |
| 153 size_in_dip, | 191 size_in_dip, |
| 154 scale_factor)), | 192 scale_factor)), |
| 155 &cancelable_task_tracker_); | 193 &cancelable_task_tracker_); |
| 156 } | 194 } |
| 157 } | 195 } |
| 158 | 196 |
| 159 std::string FaviconSource::GetMimeType(const std::string&) const { | 197 std::string FaviconSource::GetMimeType(const std::string&) const { |
| 160 // We need to explicitly return a mime type, otherwise if the user tries to | 198 // We need to explicitly return a mime type, otherwise if the user tries to |
| 161 // drag the image they get no extension. | 199 // drag the image they get no extension. |
| 162 return "image/png"; | 200 return "image/png"; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 178 const IconRequest& request, | 216 const IconRequest& request, |
| 179 const history::FaviconBitmapResult& bitmap_result) { | 217 const history::FaviconBitmapResult& bitmap_result) { |
| 180 if (bitmap_result.is_valid()) { | 218 if (bitmap_result.is_valid()) { |
| 181 // Forward the data along to the networking system. | 219 // Forward the data along to the networking system. |
| 182 request.callback.Run(bitmap_result.bitmap_data); | 220 request.callback.Run(bitmap_result.bitmap_data); |
| 183 } else if (!HandleMissingResource(request)) { | 221 } else if (!HandleMissingResource(request)) { |
| 184 SendDefaultResponse(request); | 222 SendDefaultResponse(request); |
| 185 } | 223 } |
| 186 } | 224 } |
| 187 | 225 |
| 226 void FaviconSource::SendDefaultResponse( |
| 227 const content::URLDataSource::GotDataCallback& callback) { |
| 228 SendDefaultResponse(IconRequest(callback, |
| 229 "", |
| 230 16, |
| 231 ui::SCALE_FACTOR_100P)); |
| 232 } |
| 233 |
| 188 void FaviconSource::SendDefaultResponse(const IconRequest& icon_request) { | 234 void FaviconSource::SendDefaultResponse(const IconRequest& icon_request) { |
| 189 int favicon_index; | 235 int favicon_index; |
| 190 int resource_id; | 236 int resource_id; |
| 191 switch (icon_request.size_in_dip) { | 237 switch (icon_request.size_in_dip) { |
| 192 case 64: | 238 case 64: |
| 193 favicon_index = SIZE_64; | 239 favicon_index = SIZE_64; |
| 194 resource_id = IDR_DEFAULT_FAVICON_64; | 240 resource_id = IDR_DEFAULT_FAVICON_64; |
| 195 break; | 241 break; |
| 196 case 32: | 242 case 32: |
| 197 favicon_index = SIZE_32; | 243 favicon_index = SIZE_32; |
| 198 resource_id = IDR_DEFAULT_FAVICON_32; | 244 resource_id = IDR_DEFAULT_FAVICON_32; |
| 199 break; | 245 break; |
| 200 default: | 246 default: |
| 201 favicon_index = SIZE_16; | 247 favicon_index = SIZE_16; |
| 202 resource_id = IDR_DEFAULT_FAVICON; | 248 resource_id = IDR_DEFAULT_FAVICON; |
| 203 break; | 249 break; |
| 204 } | 250 } |
| 205 base::RefCountedMemory* default_favicon = default_favicons_[favicon_index]; | 251 base::RefCountedMemory* default_favicon = default_favicons_[favicon_index]; |
| 206 | 252 |
| 207 if (!default_favicon) { | 253 if (!default_favicon) { |
| 208 ui::ScaleFactor scale_factor = icon_request.scale_factor; | 254 ui::ScaleFactor scale_factor = icon_request.scale_factor; |
| 209 default_favicon = ResourceBundle::GetSharedInstance() | 255 default_favicon = ResourceBundle::GetSharedInstance() |
| 210 .LoadDataResourceBytesForScale(resource_id, scale_factor); | 256 .LoadDataResourceBytesForScale(resource_id, scale_factor); |
| 211 default_favicons_[favicon_index] = default_favicon; | 257 default_favicons_[favicon_index] = default_favicon; |
| 212 } | 258 } |
| 213 | 259 |
| 214 icon_request.callback.Run(default_favicon); | 260 icon_request.callback.Run(default_favicon); |
| 215 } | 261 } |
| OLD | NEW |