OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/extensions/bookmark_app_helper.h" | 5 #include "chrome/browser/extensions/bookmark_app_helper.h" |
6 | 6 |
7 #include <cctype> | 7 #include <cctype> |
8 | 8 |
9 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
10 #include "chrome/browser/extensions/crx_installer.h" | 10 #include "chrome/browser/extensions/crx_installer.h" |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
105 ++it) { | 105 ++it) { |
106 WebApplicationInfo::IconInfo icon_info; | 106 WebApplicationInfo::IconInfo icon_info; |
107 icon_info.data = *it->ToSkBitmap(); | 107 icon_info.data = *it->ToSkBitmap(); |
108 icon_info.width = icon_info.data.width(); | 108 icon_info.width = icon_info.data.width(); |
109 icon_info.height = icon_info.data.height(); | 109 icon_info.height = icon_info.data.height(); |
110 web_app_info.icons.push_back(icon_info); | 110 web_app_info.icons.push_back(icon_info); |
111 } | 111 } |
112 callback.Run(web_app_info); | 112 callback.Run(web_app_info); |
113 } | 113 } |
114 | 114 |
115 std::set<int> SizesToGenerate() { | |
116 // Generate container icons from smaller icons. | |
117 const int kIconSizesToGenerate[] = { | |
118 extension_misc::EXTENSION_ICON_SMALL, | |
119 extension_misc::EXTENSION_ICON_MEDIUM, | |
120 }; | |
121 return std::set<int>(kIconSizesToGenerate, | |
122 kIconSizesToGenerate + arraysize(kIconSizesToGenerate)); | |
123 } | |
124 | |
125 void GenerateIcons(std::set<int> generate_sizes, | |
126 const GURL& app_url, | |
127 SkColor generated_icon_color, | |
128 std::map<int, SkBitmap>* bitmap_map) { | |
129 // The letter that will be painted on the generated icon. | |
130 char icon_letter = ' '; | |
131 std::string domain_and_registry( | |
132 net::registry_controlled_domains::GetDomainAndRegistry( | |
133 app_url, | |
134 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)); | |
135 if (!domain_and_registry.empty()) { | |
136 icon_letter = domain_and_registry[0]; | |
137 } else if (!app_url.host().empty()) { | |
138 icon_letter = app_url.host()[0]; | |
139 } | |
140 | |
141 // If no color has been specified, use a dark gray so it will stand out on the | |
142 // black shelf. | |
143 if (generated_icon_color == SK_ColorTRANSPARENT) | |
144 generated_icon_color = SK_ColorDKGRAY; | |
145 | |
146 for (std::set<int>::const_iterator it = generate_sizes.begin(); | |
147 it != generate_sizes.end(); ++it) { | |
148 extensions::BookmarkAppHelper::GenerateIcon( | |
149 bitmap_map, *it, generated_icon_color, icon_letter); | |
150 // Also generate the 2x resource for this size. | |
151 extensions::BookmarkAppHelper::GenerateIcon( | |
152 bitmap_map, *it * 2, generated_icon_color, icon_letter); | |
153 } | |
154 } | |
155 | |
156 void ReplaceWebAppIcons(std::map<int, SkBitmap> bitmap_map, | |
157 WebApplicationInfo* web_app_info) { | |
158 web_app_info->icons.clear(); | |
159 | |
160 // Populate the icon data into the WebApplicationInfo we are using to | |
161 // install the bookmark app. | |
162 for (std::map<int, SkBitmap>::const_iterator bitmap_map_it = | |
163 bitmap_map.begin(); | |
164 bitmap_map_it != bitmap_map.end(); ++bitmap_map_it) { | |
165 WebApplicationInfo::IconInfo icon_info; | |
166 icon_info.data = bitmap_map_it->second; | |
167 icon_info.width = icon_info.data.width(); | |
168 icon_info.height = icon_info.data.height(); | |
169 web_app_info->icons.push_back(icon_info); | |
170 } | |
171 } | |
172 | |
115 } // namespace | 173 } // namespace |
116 | 174 |
117 namespace extensions { | 175 namespace extensions { |
118 | 176 |
119 // static | 177 // static |
120 void BookmarkAppHelper::UpdateWebAppInfoFromManifest( | 178 void BookmarkAppHelper::UpdateWebAppInfoFromManifest( |
121 const content::Manifest& manifest, | 179 const content::Manifest& manifest, |
122 WebApplicationInfo* web_app_info) { | 180 WebApplicationInfo* web_app_info) { |
123 if (!manifest.short_name.is_null()) | 181 if (!manifest.short_name.is_null()) |
124 web_app_info->title = manifest.short_name.string(); | 182 web_app_info->title = manifest.short_name.string(); |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
253 bool success, | 311 bool success, |
254 const std::map<GURL, std::vector<SkBitmap> >& bitmaps) { | 312 const std::map<GURL, std::vector<SkBitmap> >& bitmaps) { |
255 // The tab has navigated away during the icon download. Cancel the bookmark | 313 // The tab has navigated away during the icon download. Cancel the bookmark |
256 // app creation. | 314 // app creation. |
257 if (!success) { | 315 if (!success) { |
258 favicon_downloader_.reset(); | 316 favicon_downloader_.reset(); |
259 callback_.Run(NULL, web_app_info_); | 317 callback_.Run(NULL, web_app_info_); |
260 return; | 318 return; |
261 } | 319 } |
262 | 320 |
263 // Add the downloaded icons. Extensions only allow certain icon sizes. First | |
264 // populate icons that match the allowed sizes exactly and then downscale | |
265 // remaining icons to the closest allowed size that doesn't yet have an icon. | |
266 std::set<int> allowed_sizes(extension_misc::kExtensionIconSizes, | |
267 extension_misc::kExtensionIconSizes + | |
268 extension_misc::kNumExtensionIconSizes); | |
269 std::vector<SkBitmap> downloaded_icons; | 321 std::vector<SkBitmap> downloaded_icons; |
270 for (FaviconDownloader::FaviconMap::const_iterator map_it = bitmaps.begin(); | 322 for (FaviconDownloader::FaviconMap::const_iterator map_it = bitmaps.begin(); |
271 map_it != bitmaps.end(); | 323 map_it != bitmaps.end(); |
272 ++map_it) { | 324 ++map_it) { |
273 for (std::vector<SkBitmap>::const_iterator bitmap_it = | 325 for (std::vector<SkBitmap>::const_iterator bitmap_it = |
274 map_it->second.begin(); | 326 map_it->second.begin(); |
275 bitmap_it != map_it->second.end(); | 327 bitmap_it != map_it->second.end(); |
276 ++bitmap_it) { | 328 ++bitmap_it) { |
277 if (bitmap_it->empty() || bitmap_it->width() != bitmap_it->height()) | 329 if (bitmap_it->empty() || bitmap_it->width() != bitmap_it->height()) |
278 continue; | 330 continue; |
279 | 331 |
280 downloaded_icons.push_back(*bitmap_it); | 332 downloaded_icons.push_back(*bitmap_it); |
281 } | 333 } |
282 } | 334 } |
283 | 335 |
284 // Add all existing icons from WebApplicationInfo. | 336 // Add all existing icons from WebApplicationInfo. |
285 for (std::vector<WebApplicationInfo::IconInfo>::const_iterator it = | 337 for (std::vector<WebApplicationInfo::IconInfo>::const_iterator it = |
286 web_app_info_.icons.begin(); | 338 web_app_info_.icons.begin(); |
287 it != web_app_info_.icons.end(); | 339 it != web_app_info_.icons.end(); |
288 ++it) { | 340 ++it) { |
289 const SkBitmap& icon = it->data; | 341 const SkBitmap& icon = it->data; |
290 if (!icon.drawsNothing() && icon.width() == icon.height()) | 342 if (!icon.drawsNothing() && icon.width() == icon.height()) |
291 downloaded_icons.push_back(icon); | 343 downloaded_icons.push_back(icon); |
292 } | 344 } |
293 | 345 |
294 web_app_info_.icons.clear(); | 346 // Add the downloaded icons. Extensions only allow certain icon sizes. First |
347 // populate icons that match the allowed sizes exactly and then downscale | |
348 // remaining icons to the closest allowed size that doesn't yet have an icon. | |
349 std::set<int> allowed_sizes(extension_misc::kExtensionIconSizes, | |
350 extension_misc::kExtensionIconSizes + | |
351 extension_misc::kNumExtensionIconSizes); | |
295 | 352 |
296 // If there are icons that don't match the accepted icon sizes, find the | 353 // If there are icons that don't match the accepted icon sizes, find the |
297 // closest bigger icon to the accepted sizes and resize the icon to it. An | 354 // closest bigger icon to the accepted sizes and resize the icon to it. An |
298 // icon will be resized and used for at most one size. | 355 // icon will be resized and used for at most one size. |
299 std::map<int, SkBitmap> resized_bitmaps( | 356 std::map<int, SkBitmap> resized_bitmaps( |
300 ConstrainBitmapsToSizes(downloaded_icons, allowed_sizes)); | 357 extensions::BookmarkAppHelper::ConstrainBitmapsToSizes(downloaded_icons, |
358 allowed_sizes)); | |
calamity
2014/12/09 03:46:11
Hmm. Technically, this is now unnecessary work. Yo
benwells
2014/12/09 08:28:35
OK. I'm just going to use the first one we find, I
| |
301 | 359 |
302 // Generate container icons from smaller icons. | 360 web_app_info_.generated_icon_color = SK_ColorTRANSPARENT; |
303 const int kIconSizesToGenerate[] = {extension_misc::EXTENSION_ICON_SMALL, | 361 // Determine the color that will be used for the icon's background/ |
calamity
2014/12/09 03:46:11
s/d\//./
benwells
2014/12/09 08:28:35
Done.
| |
304 extension_misc::EXTENSION_ICON_MEDIUM, }; | 362 if (resized_bitmaps.size()) { |
305 const std::set<int> generate_sizes( | 363 color_utils::GridSampler sampler; |
306 kIconSizesToGenerate, | 364 web_app_info_.generated_icon_color = |
307 kIconSizesToGenerate + arraysize(kIconSizesToGenerate)); | 365 color_utils::CalculateKMeanColorOfBitmap( |
308 | 366 resized_bitmaps.begin()->second); |
309 // Only generate icons if larger icons don't exist. This means the app | |
310 // launcher and the taskbar will do their best downsizing large icons and | |
311 // these icons are only generated as a last resort against upscaling a smaller | |
312 // icon. | |
313 if (resized_bitmaps.lower_bound(*generate_sizes.rbegin()) == | |
314 resized_bitmaps.end()) { | |
315 GURL app_url = web_app_info_.app_url; | |
316 | |
317 // The letter that will be painted on the generated icon. | |
318 char icon_letter = ' '; | |
319 std::string domain_and_registry( | |
320 net::registry_controlled_domains::GetDomainAndRegistry( | |
321 app_url, | |
322 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)); | |
323 if (!domain_and_registry.empty()) { | |
324 icon_letter = domain_and_registry[0]; | |
325 } else if (!app_url.host().empty()) { | |
326 icon_letter = app_url.host()[0]; | |
327 } | |
328 | |
329 // The color that will be used for the icon's background. | |
330 SkColor background_color = SK_ColorBLACK; | |
331 if (resized_bitmaps.size()) { | |
332 color_utils::GridSampler sampler; | |
333 background_color = color_utils::CalculateKMeanColorOfBitmap( | |
334 resized_bitmaps.begin()->second); | |
335 } | |
336 | |
337 for (std::set<int>::const_iterator it = generate_sizes.begin(); | |
338 it != generate_sizes.end(); | |
339 ++it) { | |
340 GenerateIcon(&resized_bitmaps, *it, background_color, icon_letter); | |
341 // Also generate the 2x resource for this size. | |
342 GenerateIcon(&resized_bitmaps, *it * 2, background_color, icon_letter); | |
343 } | |
344 } | 367 } |
345 | 368 |
346 // Populate the icon data into the WebApplicationInfo we are using to | 369 std::set<int> generate_sizes = SizesToGenerate(); |
347 // install the bookmark app. | 370 |
348 for (std::map<int, SkBitmap>::const_iterator resized_bitmaps_it = | 371 // Icons are always generated, replacing the icons that were downloaded. This |
349 resized_bitmaps.begin(); | 372 // is done so that the icons are consistent across machines. |
350 resized_bitmaps_it != resized_bitmaps.end(); | 373 // TODO(benwells): Use blob sync once it is available to sync the downloaded |
351 ++resized_bitmaps_it) { | 374 // icons, and then only generate when there are required sizes missing. |
352 WebApplicationInfo::IconInfo icon_info; | 375 resized_bitmaps.clear(); |
353 icon_info.data = resized_bitmaps_it->second; | 376 GenerateIcons(generate_sizes, web_app_info_.app_url, |
354 icon_info.width = icon_info.data.width(); | 377 web_app_info_.generated_icon_color, &resized_bitmaps); |
355 icon_info.height = icon_info.data.height(); | 378 |
356 web_app_info_.icons.push_back(icon_info); | 379 ReplaceWebAppIcons(resized_bitmaps, &web_app_info_); |
357 } | |
358 | 380 |
359 // Install the app. | 381 // Install the app. |
360 crx_installer_->InstallWebApp(web_app_info_); | 382 crx_installer_->InstallWebApp(web_app_info_); |
361 favicon_downloader_.reset(); | 383 favicon_downloader_.reset(); |
362 } | 384 } |
363 | 385 |
364 void BookmarkAppHelper::Observe(int type, | 386 void BookmarkAppHelper::Observe(int type, |
365 const content::NotificationSource& source, | 387 const content::NotificationSource& source, |
366 const content::NotificationDetails& details) { | 388 const content::NotificationDetails& details) { |
367 switch (type) { | 389 switch (type) { |
368 case extensions::NOTIFICATION_CRX_INSTALLER_DONE: { | 390 case extensions::NOTIFICATION_CRX_INSTALLER_DONE: { |
369 const Extension* extension = | 391 const Extension* extension = |
370 content::Details<const Extension>(details).ptr(); | 392 content::Details<const Extension>(details).ptr(); |
371 DCHECK(extension); | 393 DCHECK(extension); |
372 DCHECK_EQ(AppLaunchInfo::GetLaunchWebURL(extension), | 394 DCHECK_EQ(AppLaunchInfo::GetLaunchWebURL(extension), |
373 web_app_info_.app_url); | 395 web_app_info_.app_url); |
374 callback_.Run(extension, web_app_info_); | 396 callback_.Run(extension, web_app_info_); |
375 break; | 397 break; |
376 } | 398 } |
377 case extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR: | 399 case extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR: |
378 callback_.Run(NULL, web_app_info_); | 400 callback_.Run(NULL, web_app_info_); |
379 break; | 401 break; |
380 default: | 402 default: |
381 NOTREACHED(); | 403 NOTREACHED(); |
382 break; | 404 break; |
383 } | 405 } |
384 } | 406 } |
385 | 407 |
386 void CreateOrUpdateBookmarkApp(ExtensionService* service, | 408 void CreateOrUpdateBookmarkApp(ExtensionService* service, |
387 WebApplicationInfo& web_app_info) { | 409 WebApplicationInfo& web_app_info) { |
calamity
2014/12/09 03:46:11
non-const ref? Can this be changed to a pointer?
benwells
2014/12/09 08:28:35
Nice spot, done.
| |
388 scoped_refptr<extensions::CrxInstaller> installer( | 410 scoped_refptr<extensions::CrxInstaller> installer( |
389 extensions::CrxInstaller::CreateSilent(service)); | 411 extensions::CrxInstaller::CreateSilent(service)); |
390 installer->set_error_on_unsupported_requirements(true); | 412 installer->set_error_on_unsupported_requirements(true); |
413 if (web_app_info.icons.empty()) { | |
414 std::map<int, SkBitmap> bitmap_map; | |
415 GenerateIcons(SizesToGenerate(), web_app_info.app_url, | |
416 web_app_info.generated_icon_color, &bitmap_map); | |
417 ReplaceWebAppIcons(bitmap_map, &web_app_info); | |
418 } | |
419 | |
391 installer->InstallWebApp(web_app_info); | 420 installer->InstallWebApp(web_app_info); |
392 } | 421 } |
393 | 422 |
394 void GetWebApplicationInfoFromApp( | 423 void GetWebApplicationInfoFromApp( |
395 content::BrowserContext* browser_context, | 424 content::BrowserContext* browser_context, |
396 const extensions::Extension* extension, | 425 const extensions::Extension* extension, |
397 const base::Callback<void(const WebApplicationInfo&)> callback) { | 426 const base::Callback<void(const WebApplicationInfo&)> callback) { |
398 if (!extension->from_bookmark()) { | 427 if (!extension->from_bookmark()) { |
399 callback.Run(WebApplicationInfo()); | 428 callback.Run(WebApplicationInfo()); |
400 return; | 429 return; |
(...skipping 23 matching lines...) Expand all Loading... | |
424 extension, info_list, base::Bind(&OnIconsLoaded, web_app_info, callback)); | 453 extension, info_list, base::Bind(&OnIconsLoaded, web_app_info, callback)); |
425 } | 454 } |
426 | 455 |
427 bool IsValidBookmarkAppUrl(const GURL& url) { | 456 bool IsValidBookmarkAppUrl(const GURL& url) { |
428 URLPattern origin_only_pattern(Extension::kValidWebExtentSchemes); | 457 URLPattern origin_only_pattern(Extension::kValidWebExtentSchemes); |
429 origin_only_pattern.SetMatchAllURLs(true); | 458 origin_only_pattern.SetMatchAllURLs(true); |
430 return url.is_valid() && origin_only_pattern.MatchesURL(url); | 459 return url.is_valid() && origin_only_pattern.MatchesURL(url); |
431 } | 460 } |
432 | 461 |
433 } // namespace extensions | 462 } // namespace extensions |
OLD | NEW |