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 |