bookmark_app_helper.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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 7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <cctype> 8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 9effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "base/strings/utf_string_conversions.h" 10effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/extensions/crx_installer.h" 11effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/extensions/extension_service.h" 12effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/extensions/favicon_downloader.h" 13effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/extensions/tab_helper.h" 14effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/common/extensions/extension_constants.h" 15effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/common/extensions/manifest_handlers/app_launch_info.h" 16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/notification_service.h" 17effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/notification_source.h" 18effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/web_contents.h" 196d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "extensions/browser/image_loader.h" 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/notification_types.h" 21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/constants.h" 22effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "extensions/common/extension.h" 23c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/manifest_handlers/icons_handler.h" 24c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/url_pattern.h" 25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "grit/platform_locale_settings.h" 26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "net/base/registry_controlled_domains/registry_controlled_domain.h" 27effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "skia/ext/image_operations.h" 28effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "skia/ext/platform_canvas.h" 29effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "third_party/skia/include/core/SkBitmap.h" 30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/canvas.h" 33effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "ui/gfx/color_analysis.h" 34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/color_utils.h" 35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/font.h" 36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/font_list.h" 37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/image/canvas_image_source.h" 38effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "ui/gfx/image/image.h" 395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "ui/gfx/image/image_family.h" 40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "ui/gfx/rect.h" 415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liunamespace { 435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Overlays a shortcut icon over the bottom left corner of a given image. 45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class GeneratedIconImageSource : public gfx::CanvasImageSource { 46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) public: 47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) explicit GeneratedIconImageSource(char letter, SkColor color, int output_size) 48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) : gfx::CanvasImageSource(gfx::Size(output_size, output_size), false), 49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) letter_(letter), 50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) color_(color), 51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) output_size_(output_size) {} 52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) virtual ~GeneratedIconImageSource() {} 53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private: 55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // gfx::CanvasImageSource overrides: 56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) virtual void Draw(gfx::Canvas* canvas) OVERRIDE { 57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const unsigned char kLuminanceThreshold = 190; 58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const int icon_size = output_size_ * 3 / 4; 59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const int icon_inset = output_size_ / 8; 60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const size_t border_radius = output_size_ / 16; 61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const size_t font_size = output_size_ * 7 / 16; 62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string font_name = 64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) l10n_util::GetStringUTF8(IDS_SANS_SERIF_FONT_FAMILY); 65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#if defined(OS_CHROMEOS) 66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string kChromeOSFontFamily = "Noto Sans"; 67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) font_name = kChromeOSFontFamily; 68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#endif 69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Draw a rounded rect of the given |color|. 71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkPaint background_paint; 72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) background_paint.setFlags(SkPaint::kAntiAlias_Flag); 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) background_paint.setColor(color_); 74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) gfx::Rect icon_rect(icon_inset, icon_inset, icon_size, icon_size); 76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) canvas->DrawRoundRect(icon_rect, border_radius, background_paint); 77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // The text rect's size needs to be odd to center the text correctly. 79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) gfx::Rect text_rect(icon_inset, icon_inset, icon_size + 1, icon_size + 1); 80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Draw the letter onto the rounded rect. The letter's color depends on the 81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // luminance of |color|. 82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) unsigned char luminance = color_utils::GetLuminanceForColor(color_); 83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) canvas->DrawStringRectWithFlags( 84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::string16(1, std::toupper(letter_)), 85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) gfx::FontList(gfx::Font(font_name, font_size)), 86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) luminance > kLuminanceThreshold ? SK_ColorBLACK : SK_ColorWHITE, 87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) text_rect, 88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) gfx::Canvas::TEXT_ALIGN_CENTER); 89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) char letter_; 92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkColor color_; 94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int output_size_; 96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(GeneratedIconImageSource); 98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}; 99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 1005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid OnIconsLoaded( 1015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu WebApplicationInfo web_app_info, 1025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const base::Callback<void(const WebApplicationInfo&)> callback, 1035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const gfx::ImageFamily& image_family) { 1045c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (gfx::ImageFamily::const_iterator it = image_family.begin(); 1055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu it != image_family.end(); 1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ++it) { 1075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu WebApplicationInfo::IconInfo icon_info; 1085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu icon_info.data = *it->ToSkBitmap(); 1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu icon_info.width = icon_info.data.width(); 1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu icon_info.height = icon_info.data.height(); 1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu web_app_info.icons.push_back(icon_info); 1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu callback.Run(web_app_info); 1145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 1155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} // namespace 117effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochnamespace extensions { 119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// static 121effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstd::map<int, SkBitmap> BookmarkAppHelper::ConstrainBitmapsToSizes( 122effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const std::vector<SkBitmap>& bitmaps, 123effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const std::set<int>& sizes) { 124effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch std::map<int, SkBitmap> output_bitmaps; 125effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch std::map<int, SkBitmap> ordered_bitmaps; 126effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (std::vector<SkBitmap>::const_iterator it = bitmaps.begin(); 127effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch it != bitmaps.end(); 128effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ++it) { 129effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK(it->width() == it->height()); 130effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ordered_bitmaps[it->width()] = *it; 131effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 132effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 133effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch std::set<int>::const_iterator sizes_it = sizes.begin(); 134effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch std::map<int, SkBitmap>::const_iterator bitmaps_it = ordered_bitmaps.begin(); 135effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch while (sizes_it != sizes.end() && bitmaps_it != ordered_bitmaps.end()) { 136effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch int size = *sizes_it; 137effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Find the closest not-smaller bitmap. 138effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch bitmaps_it = ordered_bitmaps.lower_bound(size); 139effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ++sizes_it; 140effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Ensure the bitmap is valid and smaller than the next allowed size. 141effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (bitmaps_it != ordered_bitmaps.end() && 142effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch (sizes_it == sizes.end() || bitmaps_it->second.width() < *sizes_it)) { 143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Resize the bitmap if it does not exactly match the desired size. 144effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch output_bitmaps[size] = bitmaps_it->second.width() == size 145effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ? bitmaps_it->second 146effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch : skia::ImageOperations::Resize( 147effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch bitmaps_it->second, 148effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch skia::ImageOperations::RESIZE_LANCZOS3, 149effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch size, 150effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch size); 151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return output_bitmaps; 154effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 155effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 156effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch// static 157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void BookmarkAppHelper::GenerateIcon(std::map<int, SkBitmap>* bitmaps, 158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int output_size, 159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkColor color, 160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) char letter) { 161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Do nothing if there is already an icon of |output_size|. 162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (bitmaps->count(output_size)) 163effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return; 164effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) gfx::ImageSkia icon_image( 166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) new GeneratedIconImageSource(letter, color, output_size), 167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) gfx::Size(output_size, output_size)); 168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) icon_image.bitmap()->deepCopyTo(&(*bitmaps)[output_size]); 169effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 170effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 171effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochBookmarkAppHelper::BookmarkAppHelper(ExtensionService* service, 172effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch WebApplicationInfo web_app_info, 173effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch content::WebContents* contents) 174effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch : web_app_info_(web_app_info), 175effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch crx_installer_(extensions::CrxInstaller::CreateSilent(service)) { 176effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch registrar_.Add(this, 1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extensions::NOTIFICATION_CRX_INSTALLER_DONE, 178effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch content::Source<CrxInstaller>(crx_installer_.get())); 179effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 180effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch registrar_.Add(this, 1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR, 182effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch content::Source<CrxInstaller>(crx_installer_.get())); 183effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 184effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch crx_installer_->set_error_on_unsupported_requirements(true); 185effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 18646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (!contents) 18746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) return; 18846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 189effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Add urls from the WebApplicationInfo. 190effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch std::vector<GURL> web_app_info_icon_urls; 191effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (std::vector<WebApplicationInfo::IconInfo>::const_iterator it = 192effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch web_app_info_.icons.begin(); 193effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch it != web_app_info_.icons.end(); 194effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ++it) { 195effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (it->url.is_valid()) 196effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch web_app_info_icon_urls.push_back(it->url); 197effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 198effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 199effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch favicon_downloader_.reset( 200effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch new FaviconDownloader(contents, 201effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch web_app_info_icon_urls, 202effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::Bind(&BookmarkAppHelper::OnIconsDownloaded, 203effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::Unretained(this)))); 204effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 205effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 206effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochBookmarkAppHelper::~BookmarkAppHelper() {} 207effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 208effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid BookmarkAppHelper::Create(const CreateBookmarkAppCallback& callback) { 209effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch callback_ = callback; 21046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 21146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (favicon_downloader_.get()) 21246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) favicon_downloader_->Start(); 21346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) else 21446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) OnIconsDownloaded(true, std::map<GURL, std::vector<SkBitmap> >()); 215effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 216effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 217effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid BookmarkAppHelper::OnIconsDownloaded( 218effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch bool success, 219effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const std::map<GURL, std::vector<SkBitmap> >& bitmaps) { 220effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // The tab has navigated away during the icon download. Cancel the bookmark 221effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // app creation. 222effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (!success) { 223effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch favicon_downloader_.reset(); 224effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch callback_.Run(NULL, web_app_info_); 225effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return; 226effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 227effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 228effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Add the downloaded icons. Extensions only allow certain icon sizes. First 229effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // populate icons that match the allowed sizes exactly and then downscale 230effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // remaining icons to the closest allowed size that doesn't yet have an icon. 231effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch std::set<int> allowed_sizes(extension_misc::kExtensionIconSizes, 232effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch extension_misc::kExtensionIconSizes + 233effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch extension_misc::kNumExtensionIconSizes); 234effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch std::vector<SkBitmap> downloaded_icons; 235effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (FaviconDownloader::FaviconMap::const_iterator map_it = bitmaps.begin(); 236effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch map_it != bitmaps.end(); 237effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ++map_it) { 238effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (std::vector<SkBitmap>::const_iterator bitmap_it = 239effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch map_it->second.begin(); 240effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch bitmap_it != map_it->second.end(); 241effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ++bitmap_it) { 242effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (bitmap_it->empty() || bitmap_it->width() != bitmap_it->height()) 243effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch continue; 244effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 245effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch downloaded_icons.push_back(*bitmap_it); 246effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 247effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 248effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 24946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) // Add all existing icons from WebApplicationInfo. 25046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) for (std::vector<WebApplicationInfo::IconInfo>::const_iterator it = 25146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) web_app_info_.icons.begin(); 25246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) it != web_app_info_.icons.end(); 25346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) ++it) { 25446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) const SkBitmap& icon = it->data; 25546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) if (!icon.drawsNothing() && icon.width() == icon.height()) 25646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) downloaded_icons.push_back(icon); 25746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) } 25846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 25946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) web_app_info_.icons.clear(); 26046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) 261effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // If there are icons that don't match the accepted icon sizes, find the 262effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // closest bigger icon to the accepted sizes and resize the icon to it. An 263effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // icon will be resized and used for at most one size. 264effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch std::map<int, SkBitmap> resized_bitmaps( 265effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ConstrainBitmapsToSizes(downloaded_icons, allowed_sizes)); 266effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 267effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Generate container icons from smaller icons. 268effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const int kIconSizesToGenerate[] = {extension_misc::EXTENSION_ICON_SMALL, 269effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch extension_misc::EXTENSION_ICON_MEDIUM, }; 270effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const std::set<int> generate_sizes( 271effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch kIconSizesToGenerate, 272effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch kIconSizesToGenerate + arraysize(kIconSizesToGenerate)); 273effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 274effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Only generate icons if larger icons don't exist. This means the app 275effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // launcher and the taskbar will do their best downsizing large icons and 276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // these icons are only generated as a last resort against upscaling a smaller 277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // icon. 278effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (resized_bitmaps.lower_bound(*generate_sizes.rbegin()) == 279effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch resized_bitmaps.end()) { 280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GURL app_url = web_app_info_.app_url; 281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // The letter that will be painted on the generated icon. 283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) char icon_letter = ' '; 284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string domain_and_registry( 285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) net::registry_controlled_domains::GetDomainAndRegistry( 286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) app_url, 287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)); 288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!domain_and_registry.empty()) { 289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) icon_letter = domain_and_registry[0]; 290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else if (!app_url.host().empty()) { 291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) icon_letter = app_url.host()[0]; 292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // The color that will be used for the icon's background. 295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkColor background_color = SK_ColorBLACK; 296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (resized_bitmaps.size()) { 297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) color_utils::GridSampler sampler; 29846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) background_color = color_utils::CalculateKMeanColorOfBitmap( 29946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) resized_bitmaps.begin()->second); 300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (std::set<int>::const_iterator it = generate_sizes.begin(); 303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) it != generate_sizes.end(); 304effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ++it) { 305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GenerateIcon(&resized_bitmaps, *it, background_color, icon_letter); 306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Also generate the 2x resource for this size. 307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GenerateIcon(&resized_bitmaps, *it * 2, background_color, icon_letter); 308effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 309effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 310effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 311effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Populate the icon data into the WebApplicationInfo we are using to 312effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // install the bookmark app. 313effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (std::map<int, SkBitmap>::const_iterator resized_bitmaps_it = 314effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch resized_bitmaps.begin(); 315effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch resized_bitmaps_it != resized_bitmaps.end(); 316effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ++resized_bitmaps_it) { 317effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch WebApplicationInfo::IconInfo icon_info; 318effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch icon_info.data = resized_bitmaps_it->second; 319effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch icon_info.width = icon_info.data.width(); 320effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch icon_info.height = icon_info.data.height(); 321effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch web_app_info_.icons.push_back(icon_info); 322effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 323effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 324effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Install the app. 325effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch crx_installer_->InstallWebApp(web_app_info_); 326effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch favicon_downloader_.reset(); 327effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 328effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 329effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid BookmarkAppHelper::Observe(int type, 330effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const content::NotificationSource& source, 331effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const content::NotificationDetails& details) { 332effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch switch (type) { 3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) case extensions::NOTIFICATION_CRX_INSTALLER_DONE: { 334effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const Extension* extension = 335effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch content::Details<const Extension>(details).ptr(); 336effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK(extension); 337effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_EQ(AppLaunchInfo::GetLaunchWebURL(extension), 338effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch web_app_info_.app_url); 339effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch callback_.Run(extension, web_app_info_); 340effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch break; 341effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) case extensions::NOTIFICATION_EXTENSION_INSTALL_ERROR: 343effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch callback_.Run(NULL, web_app_info_); 344effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch break; 345effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch default: 346effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch NOTREACHED(); 347effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch break; 348effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 349effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 350effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 351e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid CreateOrUpdateBookmarkApp(ExtensionService* service, 352e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch WebApplicationInfo& web_app_info) { 353e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch scoped_refptr<extensions::CrxInstaller> installer( 354e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch extensions::CrxInstaller::CreateSilent(service)); 355e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch installer->set_error_on_unsupported_requirements(true); 356e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch installer->InstallWebApp(web_app_info); 357e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch} 358e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 3595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid GetWebApplicationInfoFromApp( 3605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu content::BrowserContext* browser_context, 3615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const extensions::Extension* extension, 3625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const base::Callback<void(const WebApplicationInfo&)> callback) { 3635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!extension->from_bookmark()) { 3645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu callback.Run(WebApplicationInfo()); 3655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 3665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu WebApplicationInfo web_app_info; 3695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu web_app_info.app_url = AppLaunchInfo::GetLaunchWebURL(extension); 3705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu web_app_info.title = base::UTF8ToUTF16(extension->non_localized_name()); 3715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu web_app_info.description = base::UTF8ToUTF16(extension->description()); 3725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu std::vector<extensions::ImageLoader::ImageRepresentation> info_list; 3745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (size_t i = 0; i < extension_misc::kNumExtensionIconSizes; ++i) { 3755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu int size = extension_misc::kExtensionIconSizes[i]; 3765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu extensions::ExtensionResource resource = 3775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu extensions::IconsInfo::GetIconResource( 3785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu extension, size, ExtensionIconSet::MATCH_EXACTLY); 3795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!resource.empty()) { 3805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu info_list.push_back(extensions::ImageLoader::ImageRepresentation( 3815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu resource, 3825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE, 3835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu gfx::Size(size, size), 3845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ui::SCALE_FACTOR_100P)); 3855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu extensions::ImageLoader::Get(browser_context)->LoadImageFamilyAsync( 3895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu extension, info_list, base::Bind(&OnIconsLoaded, web_app_info, callback)); 3905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 3915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 392c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool IsValidBookmarkAppUrl(const GURL& url) { 393c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch URLPattern origin_only_pattern(Extension::kValidWebExtentSchemes); 394c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch origin_only_pattern.SetMatchAllURLs(true); 395c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return url.is_valid() && origin_only_pattern.MatchesURL(url); 396c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 397c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 398effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} // namespace extensions 399