bookmark_app_helper.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
1effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// found in the LICENSE file.
4effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
5effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/extensions/bookmark_app_helper.h"
6effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
7effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/strings/utf_string_conversions.h"
8effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/chrome_notification_types.h"
9effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/extensions/crx_installer.h"
10effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/extensions/extension_service.h"
11effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/extensions/favicon_downloader.h"
12effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/extensions/tab_helper.h"
13effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/common/extensions/extension_constants.h"
14effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
15effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/notification_service.h"
16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/notification_source.h"
17effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/web_contents.h"
18effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "extensions/common/extension.h"
19c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/manifest_handlers/icons_handler.h"
20c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/url_pattern.h"
21effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "skia/ext/image_operations.h"
22effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "skia/ext/platform_canvas.h"
23effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "third_party/skia/include/core/SkBitmap.h"
24effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "ui/gfx/color_analysis.h"
25effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "ui/gfx/image/image.h"
26effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochnamespace extensions {
28effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
29effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// static
30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstd::map<int, SkBitmap> BookmarkAppHelper::ConstrainBitmapsToSizes(
31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::vector<SkBitmap>& bitmaps,
32effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::set<int>& sizes) {
33effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::map<int, SkBitmap> output_bitmaps;
34effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::map<int, SkBitmap> ordered_bitmaps;
35effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (std::vector<SkBitmap>::const_iterator it = bitmaps.begin();
36effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       it != bitmaps.end();
37effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       ++it) {
38effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK(it->width() == it->height());
39effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ordered_bitmaps[it->width()] = *it;
40effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::set<int>::const_iterator sizes_it = sizes.begin();
43effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::map<int, SkBitmap>::const_iterator bitmaps_it = ordered_bitmaps.begin();
44effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  while (sizes_it != sizes.end() && bitmaps_it != ordered_bitmaps.end()) {
45effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    int size = *sizes_it;
46effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // Find the closest not-smaller bitmap.
47effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    bitmaps_it = ordered_bitmaps.lower_bound(size);
48effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ++sizes_it;
49effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // Ensure the bitmap is valid and smaller than the next allowed size.
50effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (bitmaps_it != ordered_bitmaps.end() &&
51effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        (sizes_it == sizes.end() || bitmaps_it->second.width() < *sizes_it)) {
52effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      // Resize the bitmap if it does not exactly match the desired size.
53effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      output_bitmaps[size] = bitmaps_it->second.width() == size
54effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                 ? bitmaps_it->second
55effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                 : skia::ImageOperations::Resize(
56effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                       bitmaps_it->second,
57effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                       skia::ImageOperations::RESIZE_LANCZOS3,
58effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                       size,
59effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                       size);
60effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return output_bitmaps;
63effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
65effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// static
66effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid BookmarkAppHelper::GenerateContainerIcon(std::map<int, SkBitmap>* bitmaps,
67effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                              int output_size) {
68effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::map<int, SkBitmap>::const_iterator it =
69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      bitmaps->lower_bound(output_size);
70effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Do nothing if there is no icon smaller than the desired size or there is
71effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // already an icon of |output_size|.
72effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (it == bitmaps->begin() || bitmaps->count(output_size))
73effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
74effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
75effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  --it;
76effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // This is the biggest icon smaller than |output_size|.
77effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const SkBitmap& base_icon = it->second;
78effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
79effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const size_t kBorderRadius = 5;
80effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const size_t kColorStripHeight = 3;
81effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const SkColor kBorderColor = 0xFFD5D5D5;
82effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const SkColor kBackgroundColor = 0xFFFFFFFF;
83effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
84effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Create a separate canvas for the color strip.
85effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_ptr<SkCanvas> color_strip_canvas(
86effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      skia::CreateBitmapCanvas(output_size, output_size, false));
87effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(color_strip_canvas);
88effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
89effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Draw a rounded rect of the |base_icon|'s dominant color.
90effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  SkPaint color_strip_paint;
91effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  color_utils::GridSampler sampler;
92effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  color_strip_paint.setFlags(SkPaint::kAntiAlias_Flag);
93effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  color_strip_paint.setColor(color_utils::CalculateKMeanColorOfPNG(
94effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      gfx::Image::CreateFrom1xBitmap(base_icon).As1xPNGBytes(),
95effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      100,
96effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      665,
97effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      &sampler));
98effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  color_strip_canvas->drawRoundRect(SkRect::MakeWH(output_size, output_size),
99effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                    kBorderRadius,
100effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                    kBorderRadius,
101effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                    color_strip_paint);
102effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
103effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Erase the top of the rounded rect to leave a color strip.
104effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  SkPaint clear_paint;
105effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  clear_paint.setColor(SK_ColorTRANSPARENT);
106effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  clear_paint.setXfermodeMode(SkXfermode::kSrc_Mode);
107effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  color_strip_canvas->drawRect(
108effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      SkRect::MakeWH(output_size, output_size - kColorStripHeight),
109effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      clear_paint);
110effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
111effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Draw each element to an output canvas.
112effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_ptr<SkCanvas> canvas(
113effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      skia::CreateBitmapCanvas(output_size, output_size, false));
114effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  DCHECK(canvas);
115effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
116effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Draw the background.
117effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  SkPaint background_paint;
118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  background_paint.setColor(kBackgroundColor);
119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  background_paint.setFlags(SkPaint::kAntiAlias_Flag);
120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  canvas->drawRoundRect(SkRect::MakeWH(output_size, output_size),
121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        kBorderRadius,
122effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        kBorderRadius,
123effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        background_paint);
124effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
125effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Draw the color strip.
126effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  canvas->drawBitmap(
127effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      color_strip_canvas->getDevice()->accessBitmap(false), 0, 0);
128effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
129effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Draw the border.
130effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  SkPaint border_paint;
131effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  border_paint.setColor(kBorderColor);
132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  border_paint.setStyle(SkPaint::kStroke_Style);
133effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  border_paint.setFlags(SkPaint::kAntiAlias_Flag);
134effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  canvas->drawRoundRect(SkRect::MakeWH(output_size, output_size),
135effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        kBorderRadius,
136effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        kBorderRadius,
137effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                        border_paint);
138effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
139effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Draw the centered base icon to the output canvas.
140effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  canvas->drawBitmap(base_icon,
141effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                     (output_size - base_icon.width()) / 2,
142effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                     (output_size - base_icon.height()) / 2);
143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
144effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const SkBitmap& generated_icon = canvas->getDevice()->accessBitmap(false);
145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  generated_icon.deepCopyTo(&(*bitmaps)[output_size]);
146effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
148effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochBookmarkAppHelper::BookmarkAppHelper(ExtensionService* service,
149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                     WebApplicationInfo web_app_info,
150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                     content::WebContents* contents)
151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    : web_app_info_(web_app_info),
152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      crx_installer_(extensions::CrxInstaller::CreateSilent(service)) {
153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  registrar_.Add(this,
154effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 chrome::NOTIFICATION_CRX_INSTALLER_DONE,
155effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 content::Source<CrxInstaller>(crx_installer_.get()));
156effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
157effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  registrar_.Add(this,
158effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
159effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                 content::Source<CrxInstaller>(crx_installer_.get()));
160effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
161effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  crx_installer_->set_error_on_unsupported_requirements(true);
162effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
163effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Add urls from the WebApplicationInfo.
164effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::vector<GURL> web_app_info_icon_urls;
165effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (std::vector<WebApplicationInfo::IconInfo>::const_iterator it =
166effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch           web_app_info_.icons.begin();
167effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       it != web_app_info_.icons.end();
168effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       ++it) {
169effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if (it->url.is_valid())
170effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      web_app_info_icon_urls.push_back(it->url);
171effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
172effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
173effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  favicon_downloader_.reset(
174effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      new FaviconDownloader(contents,
175effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            web_app_info_icon_urls,
176effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                            base::Bind(&BookmarkAppHelper::OnIconsDownloaded,
177effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                       base::Unretained(this))));
178effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
179effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
180effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochBookmarkAppHelper::~BookmarkAppHelper() {}
181effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid BookmarkAppHelper::Create(const CreateBookmarkAppCallback& callback) {
183effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  callback_ = callback;
184effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  favicon_downloader_->Start();
185effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
186effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
187effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid BookmarkAppHelper::OnIconsDownloaded(
188effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    bool success,
189effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::map<GURL, std::vector<SkBitmap> >& bitmaps) {
190effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // The tab has navigated away during the icon download. Cancel the bookmark
191effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // app creation.
192effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (!success) {
193effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    favicon_downloader_.reset();
194effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    callback_.Run(NULL, web_app_info_);
195effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return;
196effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
197effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
198effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Add the downloaded icons. Extensions only allow certain icon sizes. First
199effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // populate icons that match the allowed sizes exactly and then downscale
200effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // remaining icons to the closest allowed size that doesn't yet have an icon.
201effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::set<int> allowed_sizes(extension_misc::kExtensionIconSizes,
202effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                              extension_misc::kExtensionIconSizes +
203effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                  extension_misc::kNumExtensionIconSizes);
204effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::vector<SkBitmap> downloaded_icons;
205effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (FaviconDownloader::FaviconMap::const_iterator map_it = bitmaps.begin();
206effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       map_it != bitmaps.end();
207effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       ++map_it) {
208effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    for (std::vector<SkBitmap>::const_iterator bitmap_it =
209effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch             map_it->second.begin();
210effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         bitmap_it != map_it->second.end();
211effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         ++bitmap_it) {
212effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      if (bitmap_it->empty() || bitmap_it->width() != bitmap_it->height())
213effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        continue;
214effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
215effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      downloaded_icons.push_back(*bitmap_it);
216effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
217effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
218effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
219effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // If there are icons that don't match the accepted icon sizes, find the
220effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // closest bigger icon to the accepted sizes and resize the icon to it. An
221effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // icon will be resized and used for at most one size.
222effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  std::map<int, SkBitmap> resized_bitmaps(
223effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      ConstrainBitmapsToSizes(downloaded_icons, allowed_sizes));
224effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
225effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Generate container icons from smaller icons.
226effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const int kIconSizesToGenerate[] = {extension_misc::EXTENSION_ICON_SMALL,
227effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                      extension_misc::EXTENSION_ICON_MEDIUM, };
228effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  const std::set<int> generate_sizes(
229effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      kIconSizesToGenerate,
230effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      kIconSizesToGenerate + arraysize(kIconSizesToGenerate));
231effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
232effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Only generate icons if larger icons don't exist. This means the app
233effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // launcher and the taskbar will do their best downsizing large icons and
234effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // these container icons are only generated as a last resort against upscaling
235effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // a smaller icon.
236effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  if (resized_bitmaps.lower_bound(*generate_sizes.rbegin()) ==
237effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      resized_bitmaps.end()) {
238effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // Generate these from biggest to smallest so we don't end up with
239effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    // concentric container icons.
240effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    for (std::set<int>::const_reverse_iterator it = generate_sizes.rbegin();
241effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         it != generate_sizes.rend();
242effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch         ++it) {
243effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      GenerateContainerIcon(&resized_bitmaps, *it);
244effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
245effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
246effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
247effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Populate the icon data into the WebApplicationInfo we are using to
248effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // install the bookmark app.
249effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (std::map<int, SkBitmap>::const_iterator resized_bitmaps_it =
250effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch           resized_bitmaps.begin();
251effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       resized_bitmaps_it != resized_bitmaps.end();
252effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch       ++resized_bitmaps_it) {
253effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    WebApplicationInfo::IconInfo icon_info;
254effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    icon_info.data = resized_bitmaps_it->second;
255effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    icon_info.width = icon_info.data.width();
256effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    icon_info.height = icon_info.data.height();
257effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    web_app_info_.icons.push_back(icon_info);
258effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
259effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
260effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // Install the app.
261effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  crx_installer_->InstallWebApp(web_app_info_);
262effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  favicon_downloader_.reset();
263effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
264effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
265effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid BookmarkAppHelper::Observe(int type,
266effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                const content::NotificationSource& source,
267effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                const content::NotificationDetails& details) {
268effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  switch (type) {
269effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    case chrome::NOTIFICATION_CRX_INSTALLER_DONE: {
270effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      const Extension* extension =
271effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch          content::Details<const Extension>(details).ptr();
272effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      DCHECK(extension);
273effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      DCHECK_EQ(AppLaunchInfo::GetLaunchWebURL(extension),
274effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                web_app_info_.app_url);
275effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      callback_.Run(extension, web_app_info_);
276effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      break;
277effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    }
278effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR:
279effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      callback_.Run(NULL, web_app_info_);
280effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      break;
281effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    default:
282effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      NOTREACHED();
283effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      break;
284effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
285effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
286effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
287e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid CreateOrUpdateBookmarkApp(ExtensionService* service,
288e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                               WebApplicationInfo& web_app_info) {
289e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  scoped_refptr<extensions::CrxInstaller> installer(
290e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      extensions::CrxInstaller::CreateSilent(service));
291e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  installer->set_error_on_unsupported_requirements(true);
292e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  installer->InstallWebApp(web_app_info);
293e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
294e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
295c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool IsValidBookmarkAppUrl(const GURL& url) {
296c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  URLPattern origin_only_pattern(Extension::kValidWebExtentSchemes);
297c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  origin_only_pattern.SetMatchAllURLs(true);
298c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return url.is_valid() && origin_only_pattern.MatchesURL(url);
299c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
300c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
301effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}  // namespace extensions
302