Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / extensions / bookmark_app_helper.cc
bloba44c002a1d22e2dee5d1f8573234960223eded56
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
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/bookmark_app_helper.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/extensions/crx_installer.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/extensions/favicon_downloader.h"
12 #include "chrome/browser/extensions/image_loader.h"
13 #include "chrome/browser/extensions/tab_helper.h"
14 #include "chrome/common/extensions/extension_constants.h"
15 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
16 #include "content/public/browser/notification_service.h"
17 #include "content/public/browser/notification_source.h"
18 #include "content/public/browser/web_contents.h"
19 #include "extensions/common/extension.h"
20 #include "extensions/common/manifest_handlers/icons_handler.h"
21 #include "extensions/common/url_pattern.h"
22 #include "skia/ext/image_operations.h"
23 #include "skia/ext/platform_canvas.h"
24 #include "third_party/skia/include/core/SkBitmap.h"
25 #include "ui/gfx/color_analysis.h"
26 #include "ui/gfx/image/image.h"
27 #include "ui/gfx/image/image_family.h"
29 namespace {
31 void OnIconsLoaded(
32 WebApplicationInfo web_app_info,
33 const base::Callback<void(const WebApplicationInfo&)> callback,
34 const gfx::ImageFamily& image_family) {
35 for (gfx::ImageFamily::const_iterator it = image_family.begin();
36 it != image_family.end();
37 ++it) {
38 WebApplicationInfo::IconInfo icon_info;
39 icon_info.data = *it->ToSkBitmap();
40 icon_info.width = icon_info.data.width();
41 icon_info.height = icon_info.data.height();
42 web_app_info.icons.push_back(icon_info);
44 callback.Run(web_app_info);
47 } // namespace
49 namespace extensions {
51 // static
52 std::map<int, SkBitmap> BookmarkAppHelper::ConstrainBitmapsToSizes(
53 const std::vector<SkBitmap>& bitmaps,
54 const std::set<int>& sizes) {
55 std::map<int, SkBitmap> output_bitmaps;
56 std::map<int, SkBitmap> ordered_bitmaps;
57 for (std::vector<SkBitmap>::const_iterator it = bitmaps.begin();
58 it != bitmaps.end();
59 ++it) {
60 DCHECK(it->width() == it->height());
61 ordered_bitmaps[it->width()] = *it;
64 std::set<int>::const_iterator sizes_it = sizes.begin();
65 std::map<int, SkBitmap>::const_iterator bitmaps_it = ordered_bitmaps.begin();
66 while (sizes_it != sizes.end() && bitmaps_it != ordered_bitmaps.end()) {
67 int size = *sizes_it;
68 // Find the closest not-smaller bitmap.
69 bitmaps_it = ordered_bitmaps.lower_bound(size);
70 ++sizes_it;
71 // Ensure the bitmap is valid and smaller than the next allowed size.
72 if (bitmaps_it != ordered_bitmaps.end() &&
73 (sizes_it == sizes.end() || bitmaps_it->second.width() < *sizes_it)) {
74 // Resize the bitmap if it does not exactly match the desired size.
75 output_bitmaps[size] = bitmaps_it->second.width() == size
76 ? bitmaps_it->second
77 : skia::ImageOperations::Resize(
78 bitmaps_it->second,
79 skia::ImageOperations::RESIZE_LANCZOS3,
80 size,
81 size);
84 return output_bitmaps;
87 // static
88 void BookmarkAppHelper::GenerateContainerIcon(std::map<int, SkBitmap>* bitmaps,
89 int output_size) {
90 std::map<int, SkBitmap>::const_iterator it =
91 bitmaps->lower_bound(output_size);
92 // Do nothing if there is no icon smaller than the desired size or there is
93 // already an icon of |output_size|.
94 if (it == bitmaps->begin() || bitmaps->count(output_size))
95 return;
97 --it;
98 // This is the biggest icon smaller than |output_size|.
99 const SkBitmap& base_icon = it->second;
101 const size_t kBorderRadius = 5;
102 const size_t kColorStripHeight = 3;
103 const SkColor kBorderColor = 0xFFD5D5D5;
104 const SkColor kBackgroundColor = 0xFFFFFFFF;
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);
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);
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);
133 // Draw each element to an output canvas.
134 scoped_ptr<SkCanvas> canvas(
135 skia::CreateBitmapCanvas(output_size, output_size, false));
136 DCHECK(canvas);
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);
147 // Draw the color strip.
148 canvas->drawBitmap(
149 color_strip_canvas->getDevice()->accessBitmap(false), 0, 0);
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);
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);
166 const SkBitmap& generated_icon = canvas->getDevice()->accessBitmap(false);
167 generated_icon.deepCopyTo(&(*bitmaps)[output_size]);
170 BookmarkAppHelper::BookmarkAppHelper(ExtensionService* service,
171 WebApplicationInfo web_app_info,
172 content::WebContents* contents)
173 : web_app_info_(web_app_info),
174 crx_installer_(extensions::CrxInstaller::CreateSilent(service)) {
175 registrar_.Add(this,
176 chrome::NOTIFICATION_CRX_INSTALLER_DONE,
177 content::Source<CrxInstaller>(crx_installer_.get()));
179 registrar_.Add(this,
180 chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
181 content::Source<CrxInstaller>(crx_installer_.get()));
183 crx_installer_->set_error_on_unsupported_requirements(true);
185 // Add urls from the WebApplicationInfo.
186 std::vector<GURL> web_app_info_icon_urls;
187 for (std::vector<WebApplicationInfo::IconInfo>::const_iterator it =
188 web_app_info_.icons.begin();
189 it != web_app_info_.icons.end();
190 ++it) {
191 if (it->url.is_valid())
192 web_app_info_icon_urls.push_back(it->url);
195 favicon_downloader_.reset(
196 new FaviconDownloader(contents,
197 web_app_info_icon_urls,
198 base::Bind(&BookmarkAppHelper::OnIconsDownloaded,
199 base::Unretained(this))));
202 BookmarkAppHelper::~BookmarkAppHelper() {}
204 void BookmarkAppHelper::Create(const CreateBookmarkAppCallback& callback) {
205 callback_ = callback;
206 favicon_downloader_->Start();
209 void BookmarkAppHelper::OnIconsDownloaded(
210 bool success,
211 const std::map<GURL, std::vector<SkBitmap> >& bitmaps) {
212 // The tab has navigated away during the icon download. Cancel the bookmark
213 // app creation.
214 if (!success) {
215 favicon_downloader_.reset();
216 callback_.Run(NULL, web_app_info_);
217 return;
220 // Add the downloaded icons. Extensions only allow certain icon sizes. First
221 // populate icons that match the allowed sizes exactly and then downscale
222 // remaining icons to the closest allowed size that doesn't yet have an icon.
223 std::set<int> allowed_sizes(extension_misc::kExtensionIconSizes,
224 extension_misc::kExtensionIconSizes +
225 extension_misc::kNumExtensionIconSizes);
226 std::vector<SkBitmap> downloaded_icons;
227 for (FaviconDownloader::FaviconMap::const_iterator map_it = bitmaps.begin();
228 map_it != bitmaps.end();
229 ++map_it) {
230 for (std::vector<SkBitmap>::const_iterator bitmap_it =
231 map_it->second.begin();
232 bitmap_it != map_it->second.end();
233 ++bitmap_it) {
234 if (bitmap_it->empty() || bitmap_it->width() != bitmap_it->height())
235 continue;
237 downloaded_icons.push_back(*bitmap_it);
241 // If there are icons that don't match the accepted icon sizes, find the
242 // closest bigger icon to the accepted sizes and resize the icon to it. An
243 // icon will be resized and used for at most one size.
244 std::map<int, SkBitmap> resized_bitmaps(
245 ConstrainBitmapsToSizes(downloaded_icons, allowed_sizes));
247 // Generate container icons from smaller icons.
248 const int kIconSizesToGenerate[] = {extension_misc::EXTENSION_ICON_SMALL,
249 extension_misc::EXTENSION_ICON_MEDIUM, };
250 const std::set<int> generate_sizes(
251 kIconSizesToGenerate,
252 kIconSizesToGenerate + arraysize(kIconSizesToGenerate));
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
256 // these container icons are only generated as a last resort against upscaling
257 // a smaller icon.
258 if (resized_bitmaps.lower_bound(*generate_sizes.rbegin()) ==
259 resized_bitmaps.end()) {
260 // Generate these from biggest to smallest so we don't end up with
261 // concentric container icons.
262 for (std::set<int>::const_reverse_iterator it = generate_sizes.rbegin();
263 it != generate_sizes.rend();
264 ++it) {
265 GenerateContainerIcon(&resized_bitmaps, *it);
269 // Populate the icon data into the WebApplicationInfo we are using to
270 // install the bookmark app.
271 for (std::map<int, SkBitmap>::const_iterator resized_bitmaps_it =
272 resized_bitmaps.begin();
273 resized_bitmaps_it != resized_bitmaps.end();
274 ++resized_bitmaps_it) {
275 WebApplicationInfo::IconInfo icon_info;
276 icon_info.data = resized_bitmaps_it->second;
277 icon_info.width = icon_info.data.width();
278 icon_info.height = icon_info.data.height();
279 web_app_info_.icons.push_back(icon_info);
282 // Install the app.
283 crx_installer_->InstallWebApp(web_app_info_);
284 favicon_downloader_.reset();
287 void BookmarkAppHelper::Observe(int type,
288 const content::NotificationSource& source,
289 const content::NotificationDetails& details) {
290 switch (type) {
291 case chrome::NOTIFICATION_CRX_INSTALLER_DONE: {
292 const Extension* extension =
293 content::Details<const Extension>(details).ptr();
294 DCHECK(extension);
295 DCHECK_EQ(AppLaunchInfo::GetLaunchWebURL(extension),
296 web_app_info_.app_url);
297 callback_.Run(extension, web_app_info_);
298 break;
300 case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR:
301 callback_.Run(NULL, web_app_info_);
302 break;
303 default:
304 NOTREACHED();
305 break;
309 void CreateOrUpdateBookmarkApp(ExtensionService* service,
310 WebApplicationInfo& web_app_info) {
311 scoped_refptr<extensions::CrxInstaller> installer(
312 extensions::CrxInstaller::CreateSilent(service));
313 installer->set_error_on_unsupported_requirements(true);
314 installer->InstallWebApp(web_app_info);
317 void GetWebApplicationInfoFromApp(
318 content::BrowserContext* browser_context,
319 const extensions::Extension* extension,
320 const base::Callback<void(const WebApplicationInfo&)> callback) {
321 if (!extension->from_bookmark()) {
322 callback.Run(WebApplicationInfo());
323 return;
326 WebApplicationInfo web_app_info;
327 web_app_info.app_url = AppLaunchInfo::GetLaunchWebURL(extension);
328 web_app_info.title = base::UTF8ToUTF16(extension->non_localized_name());
329 web_app_info.description = base::UTF8ToUTF16(extension->description());
331 std::vector<extensions::ImageLoader::ImageRepresentation> info_list;
332 for (size_t i = 0; i < extension_misc::kNumExtensionIconSizes; ++i) {
333 int size = extension_misc::kExtensionIconSizes[i];
334 extensions::ExtensionResource resource =
335 extensions::IconsInfo::GetIconResource(
336 extension, size, ExtensionIconSet::MATCH_EXACTLY);
337 if (!resource.empty()) {
338 info_list.push_back(extensions::ImageLoader::ImageRepresentation(
339 resource,
340 extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
341 gfx::Size(size, size),
342 ui::SCALE_FACTOR_100P));
346 extensions::ImageLoader::Get(browser_context)->LoadImageFamilyAsync(
347 extension, info_list, base::Bind(&OnIconsLoaded, web_app_info, callback));
350 bool IsValidBookmarkAppUrl(const GURL& url) {
351 URLPattern origin_only_pattern(Extension::kValidWebExtentSchemes);
352 origin_only_pattern.SetMatchAllURLs(true);
353 return url.is_valid() && origin_only_pattern.MatchesURL(url);
356 } // namespace extensions