| Index: chrome/browser/extensions/bookmark_app_helper.cc
|
| diff --git a/chrome/browser/extensions/bookmark_app_helper.cc b/chrome/browser/extensions/bookmark_app_helper.cc
|
| index b7e8db5e2a11c94dd8c5878f72365b2e2980b922..d0b43679bda83bea08acb2034b880b9988948046 100644
|
| --- a/chrome/browser/extensions/bookmark_app_helper.cc
|
| +++ b/chrome/browser/extensions/bookmark_app_helper.cc
|
| @@ -8,6 +8,8 @@
|
|
|
| #include "base/prefs/pref_service.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| +#include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
|
| +#include "chrome/browser/bitmap_fetcher/bitmap_fetcher_delegate.h"
|
| #include "chrome/browser/chrome_notification_types.h"
|
| #include "chrome/browser/extensions/crx_installer.h"
|
| #include "chrome/browser/extensions/extension_service.h"
|
| @@ -36,7 +38,9 @@
|
| #include "extensions/common/manifest_handlers/icons_handler.h"
|
| #include "extensions/common/url_pattern.h"
|
| #include "grit/platform_locale_settings.h"
|
| +#include "net/base/load_flags.h"
|
| #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
|
| +#include "net/url_request/url_request.h"
|
| #include "skia/ext/image_operations.h"
|
| #include "skia/ext/platform_canvas.h"
|
| #include "third_party/skia/include/core/SkBitmap.h"
|
| @@ -63,6 +67,8 @@
|
|
|
| namespace {
|
|
|
| +using extensions::BookmarkAppHelper;
|
| +
|
| // Overlays a shortcut icon over the bottom left corner of a given image.
|
| class GeneratedIconImageSource : public gfx::CanvasImageSource {
|
| public:
|
| @@ -146,10 +152,11 @@ std::set<int> SizesToGenerate() {
|
| kIconSizesToGenerate + arraysize(kIconSizesToGenerate));
|
| }
|
|
|
| -void GenerateIcons(std::set<int> generate_sizes,
|
| - const GURL& app_url,
|
| - SkColor generated_icon_color,
|
| - std::map<int, SkBitmap>* bitmap_map) {
|
| +void GenerateIcons(
|
| + std::set<int> generate_sizes,
|
| + const GURL& app_url,
|
| + SkColor generated_icon_color,
|
| + std::map<int, BookmarkAppHelper::BitmapAndSource>* bitmap_map) {
|
| // The letter that will be painted on the generated icon.
|
| char icon_letter = ' ';
|
| std::string domain_and_registry(
|
| @@ -177,23 +184,101 @@ void GenerateIcons(std::set<int> generate_sizes,
|
| }
|
| }
|
|
|
| -void ReplaceWebAppIcons(std::map<int, SkBitmap> bitmap_map,
|
| - WebApplicationInfo* web_app_info) {
|
| +void ReplaceWebAppIcons(
|
| + std::map<int, BookmarkAppHelper::BitmapAndSource> bitmap_map,
|
| + WebApplicationInfo* web_app_info) {
|
| web_app_info->icons.clear();
|
|
|
| // Populate the icon data into the WebApplicationInfo we are using to
|
| // install the bookmark app.
|
| - for (std::map<int, SkBitmap>::const_iterator bitmap_map_it =
|
| - bitmap_map.begin();
|
| - bitmap_map_it != bitmap_map.end(); ++bitmap_map_it) {
|
| + for (const auto& pair : bitmap_map) {
|
| WebApplicationInfo::IconInfo icon_info;
|
| - icon_info.data = bitmap_map_it->second;
|
| + icon_info.data = pair.second.bitmap;
|
| + icon_info.url = pair.second.source_url;
|
| icon_info.width = icon_info.data.width();
|
| icon_info.height = icon_info.data.height();
|
| web_app_info->icons.push_back(icon_info);
|
| }
|
| }
|
|
|
| +// Class to handle installing a bookmark app. Handles downloading and decoding
|
| +// the icons.
|
| +class BookmarkAppInstaller : public base::RefCounted<BookmarkAppInstaller>,
|
| + public chrome::BitmapFetcherDelegate {
|
| + public:
|
| + BookmarkAppInstaller(ExtensionService* service,
|
| + const WebApplicationInfo& web_app_info)
|
| + : service_(service), web_app_info_(web_app_info) {}
|
| +
|
| + void Run() {
|
| + for (const auto& icon : web_app_info_.icons) {
|
| + if (icon.url.is_valid())
|
| + urls_to_download_.push_back(icon.url);
|
| + }
|
| +
|
| + if (urls_to_download_.size()) {
|
| + DownloadNextImage();
|
| +
|
| + // Matched in OnFetchComplete.
|
| + AddRef();
|
| + return;
|
| + }
|
| +
|
| + FinishInstallation();
|
| + }
|
| +
|
| + private:
|
| + friend class base::RefCounted<BookmarkAppInstaller>;
|
| + ~BookmarkAppInstaller() override {}
|
| +
|
| + // BitmapFetcherDelegate:
|
| + void OnFetchComplete(const GURL& url, const SkBitmap* bitmap) override {
|
| + if (bitmap && !bitmap->empty() && bitmap->width() == bitmap->height()) {
|
| + downloaded_bitmaps_.push_back(
|
| + BookmarkAppHelper::BitmapAndSource(url, *bitmap));
|
| + }
|
| +
|
| + if (urls_to_download_.size()) {
|
| + DownloadNextImage();
|
| + return;
|
| + }
|
| +
|
| + FinishInstallation();
|
| + Release();
|
| + }
|
| +
|
| + void DownloadNextImage() {
|
| + DCHECK(urls_to_download_.size());
|
| +
|
| + bitmap_fetcher_.reset(
|
| + new chrome::BitmapFetcher(urls_to_download_.back(), this));
|
| + urls_to_download_.pop_back();
|
| + bitmap_fetcher_->Start(
|
| + service_->profile()->GetRequestContext(), std::string(),
|
| + net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
|
| + net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES);
|
| + }
|
| +
|
| + void FinishInstallation() {
|
| + std::map<int, BookmarkAppHelper::BitmapAndSource> size_map =
|
| + BookmarkAppHelper::ResizeIconsAndGenerateMissing(downloaded_bitmaps_,
|
| + &web_app_info_);
|
| + BookmarkAppHelper::UpdateWebAppIconsWithoutChangingLinks(size_map,
|
| + &web_app_info_);
|
| + scoped_refptr<extensions::CrxInstaller> installer(
|
| + extensions::CrxInstaller::CreateSilent(service_));
|
| + installer->set_error_on_unsupported_requirements(true);
|
| + installer->InstallWebApp(web_app_info_);
|
| + }
|
| +
|
| + ExtensionService* service_;
|
| + WebApplicationInfo web_app_info_;
|
| +
|
| + scoped_ptr<chrome::BitmapFetcher> bitmap_fetcher_;
|
| + std::vector<GURL> urls_to_download_;
|
| + std::vector<BookmarkAppHelper::BitmapAndSource> downloaded_bitmaps_;
|
| +};
|
| +
|
| } // namespace
|
|
|
| namespace extensions {
|
| @@ -227,10 +312,48 @@ void BookmarkAppHelper::UpdateWebAppInfoFromManifest(
|
| }
|
|
|
| // static
|
| -void BookmarkAppHelper::GenerateIcon(std::map<int, SkBitmap>* bitmaps,
|
| - int output_size,
|
| - SkColor color,
|
| - char letter) {
|
| +std::map<int, BookmarkAppHelper::BitmapAndSource>
|
| +BookmarkAppHelper::ConstrainBitmapsToSizes(
|
| + const std::vector<BookmarkAppHelper::BitmapAndSource>& bitmaps,
|
| + const std::set<int>& sizes) {
|
| + std::map<int, BitmapAndSource> output_bitmaps;
|
| + std::map<int, BitmapAndSource> ordered_bitmaps;
|
| + for (std::vector<BitmapAndSource>::const_iterator it = bitmaps.begin();
|
| + it != bitmaps.end(); ++it) {
|
| + DCHECK(it->bitmap.width() == it->bitmap.height());
|
| + ordered_bitmaps[it->bitmap.width()] = *it;
|
| + }
|
| +
|
| + std::set<int>::const_iterator sizes_it = sizes.begin();
|
| + std::map<int, BitmapAndSource>::const_iterator bitmaps_it =
|
| + ordered_bitmaps.begin();
|
| + while (sizes_it != sizes.end() && bitmaps_it != ordered_bitmaps.end()) {
|
| + int size = *sizes_it;
|
| + // Find the closest not-smaller bitmap.
|
| + bitmaps_it = ordered_bitmaps.lower_bound(size);
|
| + ++sizes_it;
|
| + // Ensure the bitmap is valid and smaller than the next allowed size.
|
| + if (bitmaps_it != ordered_bitmaps.end() &&
|
| + (sizes_it == sizes.end() ||
|
| + bitmaps_it->second.bitmap.width() < *sizes_it)) {
|
| + output_bitmaps[size] = bitmaps_it->second;
|
| + // Resize the bitmap if it does not exactly match the desired size.
|
| + if (output_bitmaps[size].bitmap.width() != size) {
|
| + output_bitmaps[size].bitmap = skia::ImageOperations::Resize(
|
| + output_bitmaps[size].bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
|
| + size, size);
|
| + }
|
| + }
|
| + }
|
| + return output_bitmaps;
|
| +}
|
| +
|
| +// static
|
| +void BookmarkAppHelper::GenerateIcon(
|
| + std::map<int, BookmarkAppHelper::BitmapAndSource>* bitmaps,
|
| + int output_size,
|
| + SkColor color,
|
| + char letter) {
|
| // Do nothing if there is already an icon of |output_size|.
|
| if (bitmaps->count(output_size))
|
| return;
|
| @@ -238,7 +361,83 @@ void BookmarkAppHelper::GenerateIcon(std::map<int, SkBitmap>* bitmaps,
|
| gfx::ImageSkia icon_image(
|
| new GeneratedIconImageSource(letter, color, output_size),
|
| gfx::Size(output_size, output_size));
|
| - icon_image.bitmap()->deepCopyTo(&(*bitmaps)[output_size]);
|
| + icon_image.bitmap()->deepCopyTo(&(*bitmaps)[output_size].bitmap);
|
| +}
|
| +
|
| +// static
|
| +std::map<int, BookmarkAppHelper::BitmapAndSource>
|
| +BookmarkAppHelper::ResizeIconsAndGenerateMissing(
|
| + std::vector<BookmarkAppHelper::BitmapAndSource> icons,
|
| + WebApplicationInfo* web_app_info) {
|
| + // Add the downloaded icons. Extensions only allow certain icon sizes. First
|
| + // populate icons that match the allowed sizes exactly and then downscale
|
| + // remaining icons to the closest allowed size that doesn't yet have an icon.
|
| + std::set<int> allowed_sizes(extension_misc::kExtensionIconSizes,
|
| + extension_misc::kExtensionIconSizes +
|
| + extension_misc::kNumExtensionIconSizes);
|
| +
|
| + // If there are icons that don't match the accepted icon sizes, find the
|
| + // closest bigger icon to the accepted sizes and resize the icon to it. An
|
| + // icon will be resized and used for at most one size.
|
| + std::map<int, BitmapAndSource> resized_bitmaps(
|
| + ConstrainBitmapsToSizes(icons, allowed_sizes));
|
| +
|
| + // Determine the color that will be used for the icon's background. For this
|
| + // the dominant color of the first icon found is used.
|
| + if (resized_bitmaps.size()) {
|
| + color_utils::GridSampler sampler;
|
| + web_app_info->generated_icon_color =
|
| + color_utils::CalculateKMeanColorOfBitmap(
|
| + resized_bitmaps.begin()->second.bitmap);
|
| + }
|
| +
|
| + std::set<int> generate_sizes;
|
| + for (int size : SizesToGenerate()) {
|
| + if (resized_bitmaps.find(size) == resized_bitmaps.end())
|
| + generate_sizes.insert(size);
|
| + }
|
| + GenerateIcons(generate_sizes, web_app_info->app_url,
|
| + web_app_info->generated_icon_color, &resized_bitmaps);
|
| +
|
| + return resized_bitmaps;
|
| +}
|
| +
|
| +// static
|
| +void BookmarkAppHelper::UpdateWebAppIconsWithoutChangingLinks(
|
| + std::map<int, BookmarkAppHelper::BitmapAndSource> bitmap_map,
|
| + WebApplicationInfo* web_app_info) {
|
| + // First add in the icon data that have urls with the url / size data from the
|
| + // original web app info, and the data from the new icons (if any).
|
| + for (auto& icon : web_app_info->icons) {
|
| + if (!icon.url.is_empty() && icon.data.empty()) {
|
| + const auto& it = bitmap_map.find(icon.width);
|
| + if (it != bitmap_map.end() && it->second.source_url == icon.url)
|
| + icon.data = it->second.bitmap;
|
| + }
|
| + }
|
| +
|
| + // Now add in any icons from the updated list that don't have URLs.
|
| + for (const auto& pair : bitmap_map) {
|
| + if (pair.second.source_url.is_empty()) {
|
| + WebApplicationInfo::IconInfo icon_info;
|
| + icon_info.data = pair.second.bitmap;
|
| + icon_info.width = pair.first;
|
| + icon_info.height = pair.first;
|
| + web_app_info->icons.push_back(icon_info);
|
| + }
|
| + }
|
| +}
|
| +
|
| +BookmarkAppHelper::BitmapAndSource::BitmapAndSource() {
|
| +}
|
| +
|
| +BookmarkAppHelper::BitmapAndSource::BitmapAndSource(const GURL& source_url_p,
|
| + const SkBitmap& bitmap_p)
|
| + : source_url(source_url_p),
|
| + bitmap(bitmap_p) {
|
| +}
|
| +
|
| +BookmarkAppHelper::BitmapAndSource::~BitmapAndSource() {
|
| }
|
|
|
| BookmarkAppHelper::BookmarkAppHelper(Profile* profile,
|
| @@ -313,7 +512,7 @@ void BookmarkAppHelper::OnIconsDownloaded(
|
| return;
|
| }
|
|
|
| - std::vector<SkBitmap> downloaded_icons;
|
| + std::vector<BitmapAndSource> downloaded_icons;
|
| for (FaviconDownloader::FaviconMap::const_iterator map_it = bitmaps.begin();
|
| map_it != bitmaps.end();
|
| ++map_it) {
|
| @@ -324,7 +523,7 @@ void BookmarkAppHelper::OnIconsDownloaded(
|
| if (bitmap_it->empty() || bitmap_it->width() != bitmap_it->height())
|
| continue;
|
|
|
| - downloaded_icons.push_back(*bitmap_it);
|
| + downloaded_icons.push_back(BitmapAndSource(map_it->first, *bitmap_it));
|
| }
|
| }
|
|
|
| @@ -334,37 +533,15 @@ void BookmarkAppHelper::OnIconsDownloaded(
|
| it != web_app_info_.icons.end();
|
| ++it) {
|
| const SkBitmap& icon = it->data;
|
| - if (!icon.drawsNothing() && icon.width() == icon.height())
|
| - downloaded_icons.push_back(icon);
|
| + if (!icon.drawsNothing() && icon.width() == icon.height()) {
|
| + downloaded_icons.push_back(BitmapAndSource(it->url, icon));
|
| + }
|
| }
|
|
|
| - // Add the downloaded icons. Extensions only allow certain icon sizes. First
|
| - // populate icons that match the allowed sizes exactly and then downscale
|
| - // remaining icons to the closest allowed size that doesn't yet have an icon.
|
| - std::set<int> allowed_sizes(extension_misc::kExtensionIconSizes,
|
| - extension_misc::kExtensionIconSizes +
|
| - extension_misc::kNumExtensionIconSizes);
|
| -
|
| web_app_info_.generated_icon_color = SK_ColorTRANSPARENT;
|
| - // Determine the color that will be used for the icon's background. For this
|
| - // the dominant color of the first icon found is used.
|
| - if (downloaded_icons.size()) {
|
| - color_utils::GridSampler sampler;
|
| - web_app_info_.generated_icon_color =
|
| - color_utils::CalculateKMeanColorOfBitmap(downloaded_icons[0]);
|
| - }
|
| -
|
| - std::set<int> generate_sizes = SizesToGenerate();
|
| -
|
| - std::map<int, SkBitmap> generated_icons;
|
| - // Icons are always generated, replacing the icons that were downloaded. This
|
| - // is done so that the icons are consistent across machines.
|
| - // TODO(benwells): Use blob sync once it is available to sync the downloaded
|
| - // icons, and then only generate when there are required sizes missing.
|
| - GenerateIcons(generate_sizes, web_app_info_.app_url,
|
| - web_app_info_.generated_icon_color, &generated_icons);
|
| -
|
| - ReplaceWebAppIcons(generated_icons, &web_app_info_);
|
| + std::map<int, BitmapAndSource> size_to_icons =
|
| + ResizeIconsAndGenerateMissing(downloaded_icons, &web_app_info_);
|
| + ReplaceWebAppIcons(size_to_icons, &web_app_info_);
|
| favicon_downloader_.reset();
|
|
|
| if (!contents_) {
|
| @@ -480,17 +657,9 @@ void BookmarkAppHelper::Observe(int type,
|
|
|
| void CreateOrUpdateBookmarkApp(ExtensionService* service,
|
| WebApplicationInfo* web_app_info) {
|
| - scoped_refptr<extensions::CrxInstaller> installer(
|
| - extensions::CrxInstaller::CreateSilent(service));
|
| - installer->set_error_on_unsupported_requirements(true);
|
| - if (web_app_info->icons.empty()) {
|
| - std::map<int, SkBitmap> bitmap_map;
|
| - GenerateIcons(SizesToGenerate(), web_app_info->app_url,
|
| - web_app_info->generated_icon_color, &bitmap_map);
|
| - ReplaceWebAppIcons(bitmap_map, web_app_info);
|
| - }
|
| -
|
| - installer->InstallWebApp(*web_app_info);
|
| + scoped_refptr<BookmarkAppInstaller> installer(
|
| + new BookmarkAppInstaller(service, *web_app_info));
|
| + installer->Run();
|
| }
|
|
|
| void GetWebApplicationInfoFromApp(
|
|
|