bookmark_app_helper.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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/chrome_notification_types.h" 11effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/extensions/crx_installer.h" 12effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/extensions/extension_service.h" 13effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/extensions/favicon_downloader.h" 145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/extensions/image_loader.h" 15effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/browser/extensions/tab_helper.h" 16effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/common/extensions/extension_constants.h" 17effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "chrome/common/extensions/manifest_handlers/app_launch_info.h" 18effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/notification_service.h" 19effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/notification_source.h" 20effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "content/public/browser/web_contents.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, 177effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch chrome::NOTIFICATION_CRX_INSTALLER_DONE, 178effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch content::Source<CrxInstaller>(crx_installer_.get())); 179effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 180effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch registrar_.Add(this, 181effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch chrome::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 186effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Add urls from the WebApplicationInfo. 187effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch std::vector<GURL> web_app_info_icon_urls; 188effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (std::vector<WebApplicationInfo::IconInfo>::const_iterator it = 189effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch web_app_info_.icons.begin(); 190effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch it != web_app_info_.icons.end(); 191effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ++it) { 192effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (it->url.is_valid()) 193effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch web_app_info_icon_urls.push_back(it->url); 194effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 195effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 196effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch favicon_downloader_.reset( 197effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch new FaviconDownloader(contents, 198effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch web_app_info_icon_urls, 199effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::Bind(&BookmarkAppHelper::OnIconsDownloaded, 200effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch base::Unretained(this)))); 201effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 202effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 203effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochBookmarkAppHelper::~BookmarkAppHelper() {} 204effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 205effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid BookmarkAppHelper::Create(const CreateBookmarkAppCallback& callback) { 206effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch callback_ = callback; 207effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch favicon_downloader_->Start(); 208effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 209effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 210effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid BookmarkAppHelper::OnIconsDownloaded( 211effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch bool success, 212effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const std::map<GURL, std::vector<SkBitmap> >& bitmaps) { 213effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // The tab has navigated away during the icon download. Cancel the bookmark 214effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // app creation. 215effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (!success) { 216effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch favicon_downloader_.reset(); 217effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch callback_.Run(NULL, web_app_info_); 218effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return; 219effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 220effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 221effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Add the downloaded icons. Extensions only allow certain icon sizes. First 222effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // populate icons that match the allowed sizes exactly and then downscale 223effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // remaining icons to the closest allowed size that doesn't yet have an icon. 224effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch std::set<int> allowed_sizes(extension_misc::kExtensionIconSizes, 225effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch extension_misc::kExtensionIconSizes + 226effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch extension_misc::kNumExtensionIconSizes); 227effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch std::vector<SkBitmap> downloaded_icons; 228effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (FaviconDownloader::FaviconMap::const_iterator map_it = bitmaps.begin(); 229effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch map_it != bitmaps.end(); 230effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ++map_it) { 231effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (std::vector<SkBitmap>::const_iterator bitmap_it = 232effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch map_it->second.begin(); 233effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch bitmap_it != map_it->second.end(); 234effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ++bitmap_it) { 235effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (bitmap_it->empty() || bitmap_it->width() != bitmap_it->height()) 236effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch continue; 237effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 238effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch downloaded_icons.push_back(*bitmap_it); 239effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 240effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 241effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 242effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // If there are icons that don't match the accepted icon sizes, find the 243effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // closest bigger icon to the accepted sizes and resize the icon to it. An 244effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // icon will be resized and used for at most one size. 245effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch std::map<int, SkBitmap> resized_bitmaps( 246effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ConstrainBitmapsToSizes(downloaded_icons, allowed_sizes)); 247effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 248effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Generate container icons from smaller icons. 249effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const int kIconSizesToGenerate[] = {extension_misc::EXTENSION_ICON_SMALL, 250effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch extension_misc::EXTENSION_ICON_MEDIUM, }; 251effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const std::set<int> generate_sizes( 252effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch kIconSizesToGenerate, 253effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch kIconSizesToGenerate + arraysize(kIconSizesToGenerate)); 254effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 255effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Only generate icons if larger icons don't exist. This means the app 256effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // launcher and the taskbar will do their best downsizing large icons and 257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // these icons are only generated as a last resort against upscaling a smaller 258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // icon. 259effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (resized_bitmaps.lower_bound(*generate_sizes.rbegin()) == 260effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch resized_bitmaps.end()) { 261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GURL app_url = web_app_info_.app_url; 262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // The letter that will be painted on the generated icon. 264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) char icon_letter = ' '; 265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string domain_and_registry( 266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) net::registry_controlled_domains::GetDomainAndRegistry( 267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) app_url, 268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)); 269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!domain_and_registry.empty()) { 270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) icon_letter = domain_and_registry[0]; 271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else if (!app_url.host().empty()) { 272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) icon_letter = app_url.host()[0]; 273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // The color that will be used for the icon's background. 276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SkColor background_color = SK_ColorBLACK; 277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (resized_bitmaps.size()) { 278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) color_utils::GridSampler sampler; 279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) background_color = color_utils::CalculateKMeanColorOfPNG( 280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) gfx::Image::CreateFrom1xBitmap(resized_bitmaps.begin()->second) 281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) .As1xPNGBytes(), 282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 100, 283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 568, 284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) &sampler); 285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (std::set<int>::const_iterator it = generate_sizes.begin(); 288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) it != generate_sizes.end(); 289effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ++it) { 290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GenerateIcon(&resized_bitmaps, *it, background_color, icon_letter); 291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Also generate the 2x resource for this size. 292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) GenerateIcon(&resized_bitmaps, *it * 2, background_color, icon_letter); 293effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 294effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 295effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 296effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Populate the icon data into the WebApplicationInfo we are using to 297effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // install the bookmark app. 298effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch for (std::map<int, SkBitmap>::const_iterator resized_bitmaps_it = 299effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch resized_bitmaps.begin(); 300effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch resized_bitmaps_it != resized_bitmaps.end(); 301effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch ++resized_bitmaps_it) { 302effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch WebApplicationInfo::IconInfo icon_info; 303effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch icon_info.data = resized_bitmaps_it->second; 304effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch icon_info.width = icon_info.data.width(); 305effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch icon_info.height = icon_info.data.height(); 306effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch web_app_info_.icons.push_back(icon_info); 307effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 308effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 309effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Install the app. 310effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch crx_installer_->InstallWebApp(web_app_info_); 311effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch favicon_downloader_.reset(); 312effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 313effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 314effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid BookmarkAppHelper::Observe(int type, 315effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const content::NotificationSource& source, 316effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const content::NotificationDetails& details) { 317effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch switch (type) { 318effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch case chrome::NOTIFICATION_CRX_INSTALLER_DONE: { 319effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch const Extension* extension = 320effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch content::Details<const Extension>(details).ptr(); 321effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK(extension); 322effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_EQ(AppLaunchInfo::GetLaunchWebURL(extension), 323effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch web_app_info_.app_url); 324effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch callback_.Run(extension, web_app_info_); 325effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch break; 326effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 327effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: 328effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch callback_.Run(NULL, web_app_info_); 329effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch break; 330effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch default: 331effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch NOTREACHED(); 332effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch break; 333effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch } 334effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} 335effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 336e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid CreateOrUpdateBookmarkApp(ExtensionService* service, 337e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch WebApplicationInfo& web_app_info) { 338e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch scoped_refptr<extensions::CrxInstaller> installer( 339e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch extensions::CrxInstaller::CreateSilent(service)); 340e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch installer->set_error_on_unsupported_requirements(true); 341e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch installer->InstallWebApp(web_app_info); 342e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch} 343e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch 3445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid GetWebApplicationInfoFromApp( 3455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu content::BrowserContext* browser_context, 3465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const extensions::Extension* extension, 3475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu const base::Callback<void(const WebApplicationInfo&)> callback) { 3485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!extension->from_bookmark()) { 3495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu callback.Run(WebApplicationInfo()); 3505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 3515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu WebApplicationInfo web_app_info; 3545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu web_app_info.app_url = AppLaunchInfo::GetLaunchWebURL(extension); 3555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu web_app_info.title = base::UTF8ToUTF16(extension->non_localized_name()); 3565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu web_app_info.description = base::UTF8ToUTF16(extension->description()); 3575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu std::vector<extensions::ImageLoader::ImageRepresentation> info_list; 3595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (size_t i = 0; i < extension_misc::kNumExtensionIconSizes; ++i) { 3605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu int size = extension_misc::kExtensionIconSizes[i]; 3615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu extensions::ExtensionResource resource = 3625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu extensions::IconsInfo::GetIconResource( 3635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu extension, size, ExtensionIconSet::MATCH_EXACTLY); 3645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!resource.empty()) { 3655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu info_list.push_back(extensions::ImageLoader::ImageRepresentation( 3665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu resource, 3675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE, 3685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu gfx::Size(size, size), 3695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ui::SCALE_FACTOR_100P)); 3705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 3725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu extensions::ImageLoader::Get(browser_context)->LoadImageFamilyAsync( 3745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu extension, info_list, base::Bind(&OnIconsLoaded, web_app_info, callback)); 3755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 3765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 377c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool IsValidBookmarkAppUrl(const GURL& url) { 378c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch URLPattern origin_only_pattern(Extension::kValidWebExtentSchemes); 379c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch origin_only_pattern.SetMatchAllURLs(true); 380c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch return url.is_valid() && origin_only_pattern.MatchesURL(url); 381c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch} 382c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 383effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch} // namespace extensions 384