Chromium Code Reviews| 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/tab_helper.h" | 14 #include "chrome/browser/extensions/tab_helper.h" |
| 13 #include "chrome/common/extensions/extension_constants.h" | 15 #include "chrome/common/extensions/extension_constants.h" |
| 14 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" | 16 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" |
| 15 #include "content/public/browser/notification_service.h" | 17 #include "content/public/browser/notification_service.h" |
| 16 #include "content/public/browser/notification_source.h" | 18 #include "content/public/browser/notification_source.h" |
| 17 #include "content/public/browser/web_contents.h" | 19 #include "content/public/browser/web_contents.h" |
| 18 #include "extensions/common/extension.h" | 20 #include "extensions/common/extension.h" |
| 19 #include "extensions/common/manifest_handlers/icons_handler.h" | 21 #include "extensions/common/manifest_handlers/icons_handler.h" |
| 20 #include "extensions/common/url_pattern.h" | 22 #include "extensions/common/url_pattern.h" |
| 23 #include "grit/app_locale_settings.h" | |
| 24 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | |
| 21 #include "skia/ext/image_operations.h" | 25 #include "skia/ext/image_operations.h" |
| 22 #include "skia/ext/platform_canvas.h" | 26 #include "skia/ext/platform_canvas.h" |
| 23 #include "third_party/skia/include/core/SkBitmap.h" | 27 #include "third_party/skia/include/core/SkBitmap.h" |
| 28 #include "ui/base/l10n/l10n_util.h" | |
| 29 #include "ui/base/resource/resource_bundle.h" | |
| 30 #include "ui/gfx/canvas.h" | |
| 24 #include "ui/gfx/color_analysis.h" | 31 #include "ui/gfx/color_analysis.h" |
| 32 #include "ui/gfx/color_utils.h" | |
| 33 #include "ui/gfx/font.h" | |
| 34 #include "ui/gfx/font_list.h" | |
| 25 #include "ui/gfx/image/image.h" | 35 #include "ui/gfx/image/image.h" |
| 36 #include "ui/gfx/rect.h" | |
| 26 | 37 |
| 27 namespace extensions { | 38 namespace extensions { |
| 28 | 39 |
| 29 // static | 40 // static |
| 30 std::map<int, SkBitmap> BookmarkAppHelper::ConstrainBitmapsToSizes( | 41 std::map<int, SkBitmap> BookmarkAppHelper::ConstrainBitmapsToSizes( |
| 31 const std::vector<SkBitmap>& bitmaps, | 42 const std::vector<SkBitmap>& bitmaps, |
| 32 const std::set<int>& sizes) { | 43 const std::set<int>& sizes) { |
| 33 std::map<int, SkBitmap> output_bitmaps; | 44 std::map<int, SkBitmap> output_bitmaps; |
| 34 std::map<int, SkBitmap> ordered_bitmaps; | 45 std::map<int, SkBitmap> ordered_bitmaps; |
| 35 for (std::vector<SkBitmap>::const_iterator it = bitmaps.begin(); | 46 for (std::vector<SkBitmap>::const_iterator it = bitmaps.begin(); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 56 bitmaps_it->second, | 67 bitmaps_it->second, |
| 57 skia::ImageOperations::RESIZE_LANCZOS3, | 68 skia::ImageOperations::RESIZE_LANCZOS3, |
| 58 size, | 69 size, |
| 59 size); | 70 size); |
| 60 } | 71 } |
| 61 } | 72 } |
| 62 return output_bitmaps; | 73 return output_bitmaps; |
| 63 } | 74 } |
| 64 | 75 |
| 65 // static | 76 // static |
| 66 void BookmarkAppHelper::GenerateContainerIcon(std::map<int, SkBitmap>* bitmaps, | 77 void BookmarkAppHelper::GenerateIcon(std::map<int, SkBitmap>* bitmaps, |
| 67 int output_size) { | 78 int output_size, |
| 68 std::map<int, SkBitmap>::const_iterator it = | 79 SkColor color, |
| 69 bitmaps->lower_bound(output_size); | 80 char letter) { |
| 70 // Do nothing if there is no icon smaller than the desired size or there is | 81 // Do nothing if there is already an icon of |output_size|. |
| 71 // already an icon of |output_size|. | 82 if (bitmaps->count(output_size)) |
| 72 if (it == bitmaps->begin() || bitmaps->count(output_size)) | |
| 73 return; | 83 return; |
| 74 | 84 |
| 75 --it; | 85 const unsigned char kLuminanceThreshold = 190; |
| 76 // This is the biggest icon smaller than |output_size|. | 86 const int icon_size = output_size * 3 / 4; |
| 77 const SkBitmap& base_icon = it->second; | 87 const int icon_inset = output_size / 8; |
| 88 const size_t border_radius = output_size / 16; | |
| 89 const size_t font_size = output_size * 7 / 16; | |
| 78 | 90 |
| 79 const size_t kBorderRadius = 5; | 91 scoped_ptr<gfx::Canvas> canvas( |
| 80 const size_t kColorStripHeight = 3; | 92 new gfx::Canvas(gfx::Size(output_size, output_size), 1.0f, false)); |
| 81 const SkColor kBorderColor = 0xFFD5D5D5; | |
| 82 const SkColor kBackgroundColor = 0xFFFFFFFF; | |
| 83 | |
| 84 // Create a separate canvas for the color strip. | |
| 85 scoped_ptr<SkCanvas> color_strip_canvas( | |
| 86 skia::CreateBitmapCanvas(output_size, output_size, false)); | |
| 87 DCHECK(color_strip_canvas); | |
| 88 | |
| 89 // Draw a rounded rect of the |base_icon|'s dominant color. | |
| 90 SkPaint color_strip_paint; | |
| 91 color_utils::GridSampler sampler; | |
| 92 color_strip_paint.setFlags(SkPaint::kAntiAlias_Flag); | |
| 93 color_strip_paint.setColor(color_utils::CalculateKMeanColorOfPNG( | |
| 94 gfx::Image::CreateFrom1xBitmap(base_icon).As1xPNGBytes(), | |
| 95 100, | |
| 96 665, | |
| 97 &sampler)); | |
| 98 color_strip_canvas->drawRoundRect(SkRect::MakeWH(output_size, output_size), | |
| 99 kBorderRadius, | |
| 100 kBorderRadius, | |
| 101 color_strip_paint); | |
| 102 | |
| 103 // Erase the top of the rounded rect to leave a color strip. | |
| 104 SkPaint clear_paint; | |
| 105 clear_paint.setColor(SK_ColorTRANSPARENT); | |
| 106 clear_paint.setXfermodeMode(SkXfermode::kSrc_Mode); | |
| 107 color_strip_canvas->drawRect( | |
| 108 SkRect::MakeWH(output_size, output_size - kColorStripHeight), | |
| 109 clear_paint); | |
| 110 | |
| 111 // Draw each element to an output canvas. | |
| 112 scoped_ptr<SkCanvas> canvas( | |
| 113 skia::CreateBitmapCanvas(output_size, output_size, false)); | |
| 114 DCHECK(canvas); | 93 DCHECK(canvas); |
| 115 | 94 |
| 116 // Draw the background. | 95 // Draw a rounded rect of the given |color|. |
| 117 SkPaint background_paint; | 96 SkPaint background_paint; |
| 118 background_paint.setColor(kBackgroundColor); | 97 background_paint.setColor(color); |
| 119 background_paint.setFlags(SkPaint::kAntiAlias_Flag); | 98 background_paint.setFlags(SkPaint::kAntiAlias_Flag); |
| 120 canvas->drawRoundRect(SkRect::MakeWH(output_size, output_size), | |
| 121 kBorderRadius, | |
| 122 kBorderRadius, | |
| 123 background_paint); | |
| 124 | 99 |
| 125 // Draw the color strip. | 100 gfx::Rect icon_rect(icon_inset, icon_inset, icon_size, icon_size); |
| 126 canvas->drawBitmap( | 101 canvas->DrawRoundRect(icon_rect, border_radius, background_paint); |
| 127 color_strip_canvas->getDevice()->accessBitmap(false), 0, 0); | |
| 128 | 102 |
| 129 // Draw the border. | 103 // The text rect's size needs to be odd to center the text correctly. |
| 130 SkPaint border_paint; | 104 gfx::Rect text_rect(icon_inset, icon_inset, icon_size + 1, icon_size + 1); |
| 131 border_paint.setColor(kBorderColor); | 105 // Draw the letter onto the rounded rect. The letter's color depends on the |
| 132 border_paint.setStyle(SkPaint::kStroke_Style); | 106 // luminance of |color|. |
| 133 border_paint.setFlags(SkPaint::kAntiAlias_Flag); | 107 unsigned char luminance = color_utils::GetLuminanceForColor(color); |
| 134 canvas->drawRoundRect(SkRect::MakeWH(output_size, output_size), | 108 canvas->DrawStringRectWithFlags( |
| 135 kBorderRadius, | 109 base::string16(1, std::toupper(letter)), |
| 136 kBorderRadius, | 110 gfx::FontList( |
| 137 border_paint); | 111 gfx::Font(l10n_util::GetStringUTF8(IDS_WEB_FONT_FAMILY), font_size)), |
| 112 luminance > kLuminanceThreshold ? SK_ColorBLACK : SK_ColorWHITE, | |
| 113 text_rect, | |
| 114 gfx::Canvas::TEXT_ALIGN_CENTER); | |
| 138 | 115 |
| 139 // Draw the centered base icon to the output canvas. | 116 gfx::ImageSkia icon_image(canvas->ExtractImageRep()); |
| 140 canvas->drawBitmap(base_icon, | 117 icon_image.bitmap()->deepCopyTo(&(*bitmaps)[output_size]); |
| 141 (output_size - base_icon.width()) / 2, | |
| 142 (output_size - base_icon.height()) / 2); | |
| 143 | |
| 144 const SkBitmap& generated_icon = canvas->getDevice()->accessBitmap(false); | |
| 145 generated_icon.deepCopyTo(&(*bitmaps)[output_size]); | |
| 146 } | 118 } |
| 147 | 119 |
| 148 BookmarkAppHelper::BookmarkAppHelper(ExtensionService* service, | 120 BookmarkAppHelper::BookmarkAppHelper(ExtensionService* service, |
| 149 WebApplicationInfo web_app_info, | 121 WebApplicationInfo web_app_info, |
| 150 content::WebContents* contents) | 122 content::WebContents* contents) |
| 151 : web_app_info_(web_app_info), | 123 : web_app_info_(web_app_info), |
| 152 crx_installer_(extensions::CrxInstaller::CreateSilent(service)) { | 124 crx_installer_(extensions::CrxInstaller::CreateSilent(service)) { |
| 153 registrar_.Add(this, | 125 registrar_.Add(this, |
| 154 chrome::NOTIFICATION_CRX_INSTALLER_DONE, | 126 chrome::NOTIFICATION_CRX_INSTALLER_DONE, |
| 155 content::Source<CrxInstaller>(crx_installer_.get())); | 127 content::Source<CrxInstaller>(crx_installer_.get())); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 224 | 196 |
| 225 // Generate container icons from smaller icons. | 197 // Generate container icons from smaller icons. |
| 226 const int kIconSizesToGenerate[] = {extension_misc::EXTENSION_ICON_SMALL, | 198 const int kIconSizesToGenerate[] = {extension_misc::EXTENSION_ICON_SMALL, |
| 227 extension_misc::EXTENSION_ICON_MEDIUM, }; | 199 extension_misc::EXTENSION_ICON_MEDIUM, }; |
| 228 const std::set<int> generate_sizes( | 200 const std::set<int> generate_sizes( |
| 229 kIconSizesToGenerate, | 201 kIconSizesToGenerate, |
| 230 kIconSizesToGenerate + arraysize(kIconSizesToGenerate)); | 202 kIconSizesToGenerate + arraysize(kIconSizesToGenerate)); |
| 231 | 203 |
| 232 // Only generate icons if larger icons don't exist. This means the app | 204 // Only generate icons if larger icons don't exist. This means the app |
| 233 // launcher and the taskbar will do their best downsizing large icons and | 205 // launcher and the taskbar will do their best downsizing large icons and |
| 234 // these container icons are only generated as a last resort against upscaling | 206 // these icons are only generated as a last resort against upscaling a smaller |
| 235 // a smaller icon. | 207 // icon. |
| 236 if (resized_bitmaps.lower_bound(*generate_sizes.rbegin()) == | 208 if (resized_bitmaps.lower_bound(*generate_sizes.rbegin()) == |
| 237 resized_bitmaps.end()) { | 209 resized_bitmaps.end()) { |
| 238 // Generate these from biggest to smallest so we don't end up with | 210 GURL app_url = web_app_info_.app_url; |
| 239 // concentric container icons. | 211 |
| 240 for (std::set<int>::const_reverse_iterator it = generate_sizes.rbegin(); | 212 // The letter that will be painted on the generated icon. |
| 241 it != generate_sizes.rend(); | 213 char icon_letter = ' '; |
| 214 std::string domain_and_registry( | |
| 215 net::registry_controlled_domains::GetDomainAndRegistry( | |
| 216 app_url, | |
| 217 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)); | |
| 218 if (!domain_and_registry.empty()) { | |
| 219 icon_letter = domain_and_registry[0]; | |
| 220 } else if (!app_url.host().empty()) { | |
| 221 icon_letter = app_url.host()[0]; | |
| 222 } | |
| 223 | |
| 224 // The color that will be used for the icon's background. | |
| 225 SkColor background_color = SK_ColorBLACK; | |
| 226 if (resized_bitmaps.size()) { | |
| 227 color_utils::GridSampler sampler; | |
| 228 background_color = color_utils::CalculateKMeanColorOfPNG( | |
| 229 gfx::Image::CreateFrom1xBitmap(resized_bitmaps.begin()->second) | |
| 230 .As1xPNGBytes(), | |
| 231 100, | |
| 232 658, | |
| 233 &sampler); | |
| 234 } | |
| 235 | |
| 236 for (std::set<int>::const_iterator it = generate_sizes.begin(); | |
| 237 it != generate_sizes.end(); | |
| 242 ++it) { | 238 ++it) { |
| 243 GenerateContainerIcon(&resized_bitmaps, *it); | 239 GenerateIcon(&resized_bitmaps, *it, background_color, icon_letter); |
| 240 // Also generate the 2x resource for this size. | |
|
benwells
2014/04/24 03:35:58
This seems to be new to this patch. Can you call t
calamity
2014/04/24 04:28:39
Done.
| |
| 241 GenerateIcon(&resized_bitmaps, *it * 2, background_color, icon_letter); | |
| 244 } | 242 } |
| 245 } | 243 } |
| 246 | 244 |
| 247 // Populate the icon data into the WebApplicationInfo we are using to | 245 // Populate the icon data into the WebApplicationInfo we are using to |
| 248 // install the bookmark app. | 246 // install the bookmark app. |
| 249 for (std::map<int, SkBitmap>::const_iterator resized_bitmaps_it = | 247 for (std::map<int, SkBitmap>::const_iterator resized_bitmaps_it = |
| 250 resized_bitmaps.begin(); | 248 resized_bitmaps.begin(); |
| 251 resized_bitmaps_it != resized_bitmaps.end(); | 249 resized_bitmaps_it != resized_bitmaps.end(); |
| 252 ++resized_bitmaps_it) { | 250 ++resized_bitmaps_it) { |
| 253 WebApplicationInfo::IconInfo icon_info; | 251 WebApplicationInfo::IconInfo icon_info; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 292 installer->InstallWebApp(web_app_info); | 290 installer->InstallWebApp(web_app_info); |
| 293 } | 291 } |
| 294 | 292 |
| 295 bool IsValidBookmarkAppUrl(const GURL& url) { | 293 bool IsValidBookmarkAppUrl(const GURL& url) { |
| 296 URLPattern origin_only_pattern(Extension::kValidWebExtentSchemes); | 294 URLPattern origin_only_pattern(Extension::kValidWebExtentSchemes); |
| 297 origin_only_pattern.SetMatchAllURLs(true); | 295 origin_only_pattern.SetMatchAllURLs(true); |
| 298 return url.is_valid() && origin_only_pattern.MatchesURL(url); | 296 return url.is_valid() && origin_only_pattern.MatchesURL(url); |
| 299 } | 297 } |
| 300 | 298 |
| 301 } // namespace extensions | 299 } // namespace extensions |
| OLD | NEW |