| 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> |
| 8 |
| 7 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
| 8 #include "chrome/browser/chrome_notification_types.h" | 10 #include "chrome/browser/chrome_notification_types.h" |
| 9 #include "chrome/browser/extensions/crx_installer.h" | 11 #include "chrome/browser/extensions/crx_installer.h" |
| 10 #include "chrome/browser/extensions/extension_service.h" | 12 #include "chrome/browser/extensions/extension_service.h" |
| 11 #include "chrome/browser/extensions/favicon_downloader.h" | 13 #include "chrome/browser/extensions/favicon_downloader.h" |
| 12 #include "chrome/browser/extensions/image_loader.h" | 14 #include "chrome/browser/extensions/image_loader.h" |
| 13 #include "chrome/browser/extensions/tab_helper.h" | 15 #include "chrome/browser/extensions/tab_helper.h" |
| 14 #include "chrome/common/extensions/extension_constants.h" | 16 #include "chrome/common/extensions/extension_constants.h" |
| 15 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" | 17 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" |
| 16 #include "content/public/browser/notification_service.h" | 18 #include "content/public/browser/notification_service.h" |
| 17 #include "content/public/browser/notification_source.h" | 19 #include "content/public/browser/notification_source.h" |
| 18 #include "content/public/browser/web_contents.h" | 20 #include "content/public/browser/web_contents.h" |
| 19 #include "extensions/common/extension.h" | 21 #include "extensions/common/extension.h" |
| 20 #include "extensions/common/manifest_handlers/icons_handler.h" | 22 #include "extensions/common/manifest_handlers/icons_handler.h" |
| 21 #include "extensions/common/url_pattern.h" | 23 #include "extensions/common/url_pattern.h" |
| 24 #include "grit/platform_locale_settings.h" |
| 25 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| 22 #include "skia/ext/image_operations.h" | 26 #include "skia/ext/image_operations.h" |
| 23 #include "skia/ext/platform_canvas.h" | 27 #include "skia/ext/platform_canvas.h" |
| 24 #include "third_party/skia/include/core/SkBitmap.h" | 28 #include "third_party/skia/include/core/SkBitmap.h" |
| 29 #include "ui/base/l10n/l10n_util.h" |
| 30 #include "ui/base/resource/resource_bundle.h" |
| 31 #include "ui/gfx/canvas.h" |
| 25 #include "ui/gfx/color_analysis.h" | 32 #include "ui/gfx/color_analysis.h" |
| 33 #include "ui/gfx/color_utils.h" |
| 34 #include "ui/gfx/font.h" |
| 35 #include "ui/gfx/font_list.h" |
| 36 #include "ui/gfx/image/canvas_image_source.h" |
| 26 #include "ui/gfx/image/image.h" | 37 #include "ui/gfx/image/image.h" |
| 27 #include "ui/gfx/image/image_family.h" | 38 #include "ui/gfx/image/image_family.h" |
| 39 #include "ui/gfx/rect.h" |
| 28 | 40 |
| 29 namespace { | 41 namespace { |
| 30 | 42 |
| 43 // Overlays a shortcut icon over the bottom left corner of a given image. |
| 44 class GeneratedIconImageSource : public gfx::CanvasImageSource { |
| 45 public: |
| 46 explicit GeneratedIconImageSource(char letter, SkColor color, int output_size) |
| 47 : gfx::CanvasImageSource(gfx::Size(output_size, output_size), false), |
| 48 letter_(letter), |
| 49 color_(color), |
| 50 output_size_(output_size) {} |
| 51 virtual ~GeneratedIconImageSource() {} |
| 52 |
| 53 private: |
| 54 // gfx::CanvasImageSource overrides: |
| 55 virtual void Draw(gfx::Canvas* canvas) OVERRIDE { |
| 56 const unsigned char kLuminanceThreshold = 190; |
| 57 const int icon_size = output_size_ * 3 / 4; |
| 58 const int icon_inset = output_size_ / 8; |
| 59 const size_t border_radius = output_size_ / 16; |
| 60 const size_t font_size = output_size_ * 7 / 16; |
| 61 |
| 62 std::string font_name = |
| 63 l10n_util::GetStringUTF8(IDS_SANS_SERIF_FONT_FAMILY); |
| 64 #if defined(OS_CHROMEOS) |
| 65 const std::string kChromeOSFontFamily = "Noto Sans"; |
| 66 font_name = kChromeOSFontFamily; |
| 67 #endif |
| 68 |
| 69 // Draw a rounded rect of the given |color|. |
| 70 SkPaint background_paint; |
| 71 background_paint.setFlags(SkPaint::kAntiAlias_Flag); |
| 72 background_paint.setColor(color_); |
| 73 |
| 74 gfx::Rect icon_rect(icon_inset, icon_inset, icon_size, icon_size); |
| 75 canvas->DrawRoundRect(icon_rect, border_radius, background_paint); |
| 76 |
| 77 // The text rect's size needs to be odd to center the text correctly. |
| 78 gfx::Rect text_rect(icon_inset, icon_inset, icon_size + 1, icon_size + 1); |
| 79 // Draw the letter onto the rounded rect. The letter's color depends on the |
| 80 // luminance of |color|. |
| 81 unsigned char luminance = color_utils::GetLuminanceForColor(color_); |
| 82 canvas->DrawStringRectWithFlags( |
| 83 base::string16(1, std::toupper(letter_)), |
| 84 gfx::FontList(gfx::Font(font_name, font_size)), |
| 85 luminance > kLuminanceThreshold ? SK_ColorBLACK : SK_ColorWHITE, |
| 86 text_rect, |
| 87 gfx::Canvas::TEXT_ALIGN_CENTER); |
| 88 } |
| 89 |
| 90 char letter_; |
| 91 |
| 92 SkColor color_; |
| 93 |
| 94 int output_size_; |
| 95 |
| 96 DISALLOW_COPY_AND_ASSIGN(GeneratedIconImageSource); |
| 97 }; |
| 98 |
| 31 void OnIconsLoaded( | 99 void OnIconsLoaded( |
| 32 WebApplicationInfo web_app_info, | 100 WebApplicationInfo web_app_info, |
| 33 const base::Callback<void(const WebApplicationInfo&)> callback, | 101 const base::Callback<void(const WebApplicationInfo&)> callback, |
| 34 const gfx::ImageFamily& image_family) { | 102 const gfx::ImageFamily& image_family) { |
| 35 for (gfx::ImageFamily::const_iterator it = image_family.begin(); | 103 for (gfx::ImageFamily::const_iterator it = image_family.begin(); |
| 36 it != image_family.end(); | 104 it != image_family.end(); |
| 37 ++it) { | 105 ++it) { |
| 38 WebApplicationInfo::IconInfo icon_info; | 106 WebApplicationInfo::IconInfo icon_info; |
| 39 icon_info.data = *it->ToSkBitmap(); | 107 icon_info.data = *it->ToSkBitmap(); |
| 40 icon_info.width = icon_info.data.width(); | 108 icon_info.width = icon_info.data.width(); |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 bitmaps_it->second, | 146 bitmaps_it->second, |
| 79 skia::ImageOperations::RESIZE_LANCZOS3, | 147 skia::ImageOperations::RESIZE_LANCZOS3, |
| 80 size, | 148 size, |
| 81 size); | 149 size); |
| 82 } | 150 } |
| 83 } | 151 } |
| 84 return output_bitmaps; | 152 return output_bitmaps; |
| 85 } | 153 } |
| 86 | 154 |
| 87 // static | 155 // static |
| 88 void BookmarkAppHelper::GenerateContainerIcon(std::map<int, SkBitmap>* bitmaps, | 156 void BookmarkAppHelper::GenerateIcon(std::map<int, SkBitmap>* bitmaps, |
| 89 int output_size) { | 157 int output_size, |
| 90 std::map<int, SkBitmap>::const_iterator it = | 158 SkColor color, |
| 91 bitmaps->lower_bound(output_size); | 159 char letter) { |
| 92 // Do nothing if there is no icon smaller than the desired size or there is | 160 // Do nothing if there is already an icon of |output_size|. |
| 93 // already an icon of |output_size|. | 161 if (bitmaps->count(output_size)) |
| 94 if (it == bitmaps->begin() || bitmaps->count(output_size)) | |
| 95 return; | 162 return; |
| 96 | 163 |
| 97 --it; | 164 gfx::ImageSkia icon_image( |
| 98 // This is the biggest icon smaller than |output_size|. | 165 new GeneratedIconImageSource(letter, color, output_size), |
| 99 const SkBitmap& base_icon = it->second; | 166 gfx::Size(output_size, output_size)); |
| 100 | 167 icon_image.bitmap()->deepCopyTo(&(*bitmaps)[output_size]); |
| 101 const size_t kBorderRadius = 5; | |
| 102 const size_t kColorStripHeight = 3; | |
| 103 const SkColor kBorderColor = 0xFFD5D5D5; | |
| 104 const SkColor kBackgroundColor = 0xFFFFFFFF; | |
| 105 | |
| 106 // Create a separate canvas for the color strip. | |
| 107 scoped_ptr<SkCanvas> color_strip_canvas( | |
| 108 skia::CreateBitmapCanvas(output_size, output_size, false)); | |
| 109 DCHECK(color_strip_canvas); | |
| 110 | |
| 111 // Draw a rounded rect of the |base_icon|'s dominant color. | |
| 112 SkPaint color_strip_paint; | |
| 113 color_utils::GridSampler sampler; | |
| 114 color_strip_paint.setFlags(SkPaint::kAntiAlias_Flag); | |
| 115 color_strip_paint.setColor(color_utils::CalculateKMeanColorOfPNG( | |
| 116 gfx::Image::CreateFrom1xBitmap(base_icon).As1xPNGBytes(), | |
| 117 100, | |
| 118 665, | |
| 119 &sampler)); | |
| 120 color_strip_canvas->drawRoundRect(SkRect::MakeWH(output_size, output_size), | |
| 121 kBorderRadius, | |
| 122 kBorderRadius, | |
| 123 color_strip_paint); | |
| 124 | |
| 125 // Erase the top of the rounded rect to leave a color strip. | |
| 126 SkPaint clear_paint; | |
| 127 clear_paint.setColor(SK_ColorTRANSPARENT); | |
| 128 clear_paint.setXfermodeMode(SkXfermode::kSrc_Mode); | |
| 129 color_strip_canvas->drawRect( | |
| 130 SkRect::MakeWH(output_size, output_size - kColorStripHeight), | |
| 131 clear_paint); | |
| 132 | |
| 133 // Draw each element to an output canvas. | |
| 134 scoped_ptr<SkCanvas> canvas( | |
| 135 skia::CreateBitmapCanvas(output_size, output_size, false)); | |
| 136 DCHECK(canvas); | |
| 137 | |
| 138 // Draw the background. | |
| 139 SkPaint background_paint; | |
| 140 background_paint.setColor(kBackgroundColor); | |
| 141 background_paint.setFlags(SkPaint::kAntiAlias_Flag); | |
| 142 canvas->drawRoundRect(SkRect::MakeWH(output_size, output_size), | |
| 143 kBorderRadius, | |
| 144 kBorderRadius, | |
| 145 background_paint); | |
| 146 | |
| 147 // Draw the color strip. | |
| 148 canvas->drawBitmap( | |
| 149 color_strip_canvas->getDevice()->accessBitmap(false), 0, 0); | |
| 150 | |
| 151 // Draw the border. | |
| 152 SkPaint border_paint; | |
| 153 border_paint.setColor(kBorderColor); | |
| 154 border_paint.setStyle(SkPaint::kStroke_Style); | |
| 155 border_paint.setFlags(SkPaint::kAntiAlias_Flag); | |
| 156 canvas->drawRoundRect(SkRect::MakeWH(output_size, output_size), | |
| 157 kBorderRadius, | |
| 158 kBorderRadius, | |
| 159 border_paint); | |
| 160 | |
| 161 // Draw the centered base icon to the output canvas. | |
| 162 canvas->drawBitmap(base_icon, | |
| 163 (output_size - base_icon.width()) / 2, | |
| 164 (output_size - base_icon.height()) / 2); | |
| 165 | |
| 166 const SkBitmap& generated_icon = canvas->getDevice()->accessBitmap(false); | |
| 167 generated_icon.deepCopyTo(&(*bitmaps)[output_size]); | |
| 168 } | 168 } |
| 169 | 169 |
| 170 BookmarkAppHelper::BookmarkAppHelper(ExtensionService* service, | 170 BookmarkAppHelper::BookmarkAppHelper(ExtensionService* service, |
| 171 WebApplicationInfo web_app_info, | 171 WebApplicationInfo web_app_info, |
| 172 content::WebContents* contents) | 172 content::WebContents* contents) |
| 173 : web_app_info_(web_app_info), | 173 : web_app_info_(web_app_info), |
| 174 crx_installer_(extensions::CrxInstaller::CreateSilent(service)) { | 174 crx_installer_(extensions::CrxInstaller::CreateSilent(service)) { |
| 175 registrar_.Add(this, | 175 registrar_.Add(this, |
| 176 chrome::NOTIFICATION_CRX_INSTALLER_DONE, | 176 chrome::NOTIFICATION_CRX_INSTALLER_DONE, |
| 177 content::Source<CrxInstaller>(crx_installer_.get())); | 177 content::Source<CrxInstaller>(crx_installer_.get())); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 | 246 |
| 247 // Generate container icons from smaller icons. | 247 // Generate container icons from smaller icons. |
| 248 const int kIconSizesToGenerate[] = {extension_misc::EXTENSION_ICON_SMALL, | 248 const int kIconSizesToGenerate[] = {extension_misc::EXTENSION_ICON_SMALL, |
| 249 extension_misc::EXTENSION_ICON_MEDIUM, }; | 249 extension_misc::EXTENSION_ICON_MEDIUM, }; |
| 250 const std::set<int> generate_sizes( | 250 const std::set<int> generate_sizes( |
| 251 kIconSizesToGenerate, | 251 kIconSizesToGenerate, |
| 252 kIconSizesToGenerate + arraysize(kIconSizesToGenerate)); | 252 kIconSizesToGenerate + arraysize(kIconSizesToGenerate)); |
| 253 | 253 |
| 254 // Only generate icons if larger icons don't exist. This means the app | 254 // Only generate icons if larger icons don't exist. This means the app |
| 255 // launcher and the taskbar will do their best downsizing large icons and | 255 // launcher and the taskbar will do their best downsizing large icons and |
| 256 // these container icons are only generated as a last resort against upscaling | 256 // these icons are only generated as a last resort against upscaling a smaller |
| 257 // a smaller icon. | 257 // icon. |
| 258 if (resized_bitmaps.lower_bound(*generate_sizes.rbegin()) == | 258 if (resized_bitmaps.lower_bound(*generate_sizes.rbegin()) == |
| 259 resized_bitmaps.end()) { | 259 resized_bitmaps.end()) { |
| 260 // Generate these from biggest to smallest so we don't end up with | 260 GURL app_url = web_app_info_.app_url; |
| 261 // concentric container icons. | 261 |
| 262 for (std::set<int>::const_reverse_iterator it = generate_sizes.rbegin(); | 262 // The letter that will be painted on the generated icon. |
| 263 it != generate_sizes.rend(); | 263 char icon_letter = ' '; |
| 264 std::string domain_and_registry( |
| 265 net::registry_controlled_domains::GetDomainAndRegistry( |
| 266 app_url, |
| 267 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)); |
| 268 if (!domain_and_registry.empty()) { |
| 269 icon_letter = domain_and_registry[0]; |
| 270 } else if (!app_url.host().empty()) { |
| 271 icon_letter = app_url.host()[0]; |
| 272 } |
| 273 |
| 274 // The color that will be used for the icon's background. |
| 275 SkColor background_color = SK_ColorBLACK; |
| 276 if (resized_bitmaps.size()) { |
| 277 color_utils::GridSampler sampler; |
| 278 background_color = color_utils::CalculateKMeanColorOfPNG( |
| 279 gfx::Image::CreateFrom1xBitmap(resized_bitmaps.begin()->second) |
| 280 .As1xPNGBytes(), |
| 281 100, |
| 282 568, |
| 283 &sampler); |
| 284 } |
| 285 |
| 286 for (std::set<int>::const_iterator it = generate_sizes.begin(); |
| 287 it != generate_sizes.end(); |
| 264 ++it) { | 288 ++it) { |
| 265 GenerateContainerIcon(&resized_bitmaps, *it); | 289 GenerateIcon(&resized_bitmaps, *it, background_color, icon_letter); |
| 290 // Also generate the 2x resource for this size. |
| 291 GenerateIcon(&resized_bitmaps, *it * 2, background_color, icon_letter); |
| 266 } | 292 } |
| 267 } | 293 } |
| 268 | 294 |
| 269 // Populate the icon data into the WebApplicationInfo we are using to | 295 // Populate the icon data into the WebApplicationInfo we are using to |
| 270 // install the bookmark app. | 296 // install the bookmark app. |
| 271 for (std::map<int, SkBitmap>::const_iterator resized_bitmaps_it = | 297 for (std::map<int, SkBitmap>::const_iterator resized_bitmaps_it = |
| 272 resized_bitmaps.begin(); | 298 resized_bitmaps.begin(); |
| 273 resized_bitmaps_it != resized_bitmaps.end(); | 299 resized_bitmaps_it != resized_bitmaps.end(); |
| 274 ++resized_bitmaps_it) { | 300 ++resized_bitmaps_it) { |
| 275 WebApplicationInfo::IconInfo icon_info; | 301 WebApplicationInfo::IconInfo icon_info; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 347 extension, info_list, base::Bind(&OnIconsLoaded, web_app_info, callback)); | 373 extension, info_list, base::Bind(&OnIconsLoaded, web_app_info, callback)); |
| 348 } | 374 } |
| 349 | 375 |
| 350 bool IsValidBookmarkAppUrl(const GURL& url) { | 376 bool IsValidBookmarkAppUrl(const GURL& url) { |
| 351 URLPattern origin_only_pattern(Extension::kValidWebExtentSchemes); | 377 URLPattern origin_only_pattern(Extension::kValidWebExtentSchemes); |
| 352 origin_only_pattern.SetMatchAllURLs(true); | 378 origin_only_pattern.SetMatchAllURLs(true); |
| 353 return url.is_valid() && origin_only_pattern.MatchesURL(url); | 379 return url.is_valid() && origin_only_pattern.MatchesURL(url); |
| 354 } | 380 } |
| 355 | 381 |
| 356 } // namespace extensions | 382 } // namespace extensions |
| OLD | NEW |