1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/extensions/extension_icon_manager.h" 6 7#include "base/bind.h" 8#include "base/logging.h" 9#include "base/stl_util.h" 10#include "extensions/browser/image_loader.h" 11#include "extensions/common/constants.h" 12#include "extensions/common/extension.h" 13#include "extensions/common/extension_icon_set.h" 14#include "extensions/common/extension_resource.h" 15#include "extensions/common/manifest_handlers/icons_handler.h" 16#include "grit/theme_resources.h" 17#include "skia/ext/image_operations.h" 18#include "ui/base/resource/resource_bundle.h" 19#include "ui/gfx/canvas.h" 20#include "ui/gfx/color_utils.h" 21#include "ui/gfx/favicon_size.h" 22#include "ui/gfx/image/image.h" 23#include "ui/gfx/size.h" 24#include "ui/gfx/skbitmap_operations.h" 25 26namespace { 27 28// Helper function to create a new bitmap with |padding| amount of empty space 29// around the original bitmap. 30static SkBitmap ApplyPadding(const SkBitmap& source, 31 const gfx::Insets& padding) { 32 scoped_ptr<gfx::Canvas> result( 33 new gfx::Canvas(gfx::Size(source.width() + padding.width(), 34 source.height() + padding.height()), 35 1.0f, 36 false)); 37 result->DrawImageInt( 38 gfx::ImageSkia::CreateFrom1xBitmap(source), 39 0, 0, source.width(), source.height(), 40 padding.left(), padding.top(), source.width(), source.height(), 41 false); 42 return result->ExtractImageRep().sk_bitmap(); 43} 44 45} // namespace 46 47ExtensionIconManager::ExtensionIconManager() 48 : monochrome_(false), 49 weak_ptr_factory_(this) { 50} 51 52ExtensionIconManager::~ExtensionIconManager() { 53} 54 55void ExtensionIconManager::LoadIcon(content::BrowserContext* context, 56 const extensions::Extension* extension) { 57 extensions::ExtensionResource icon_resource = 58 extensions::IconsInfo::GetIconResource( 59 extension, 60 extension_misc::EXTENSION_ICON_BITTY, 61 ExtensionIconSet::MATCH_BIGGER); 62 if (!icon_resource.extension_root().empty()) { 63 // Insert into pending_icons_ first because LoadImage can call us back 64 // synchronously if the image is already cached. 65 pending_icons_.insert(extension->id()); 66 extensions::ImageLoader* loader = extensions::ImageLoader::Get(context); 67 loader->LoadImageAsync(extension, icon_resource, 68 gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize), 69 base::Bind( 70 &ExtensionIconManager::OnImageLoaded, 71 weak_ptr_factory_.GetWeakPtr(), 72 extension->id())); 73 } 74} 75 76const SkBitmap& ExtensionIconManager::GetIcon(const std::string& extension_id) { 77 const SkBitmap* result = NULL; 78 if (ContainsKey(icons_, extension_id)) { 79 result = &icons_[extension_id]; 80 } else { 81 EnsureDefaultIcon(); 82 result = &default_icon_; 83 } 84 DCHECK(result); 85 DCHECK_EQ(gfx::kFaviconSize + padding_.width(), result->width()); 86 DCHECK_EQ(gfx::kFaviconSize + padding_.height(), result->height()); 87 return *result; 88} 89 90void ExtensionIconManager::RemoveIcon(const std::string& extension_id) { 91 icons_.erase(extension_id); 92 pending_icons_.erase(extension_id); 93} 94 95void ExtensionIconManager::OnImageLoaded(const std::string& extension_id, 96 const gfx::Image& image) { 97 if (image.IsEmpty()) 98 return; 99 100 // We may have removed the icon while waiting for it to load. In that case, 101 // do nothing. 102 if (!ContainsKey(pending_icons_, extension_id)) 103 return; 104 105 pending_icons_.erase(extension_id); 106 icons_[extension_id] = ApplyTransforms(*image.ToSkBitmap()); 107} 108 109void ExtensionIconManager::EnsureDefaultIcon() { 110 if (default_icon_.empty()) { 111 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 112 SkBitmap src = rb.GetImageNamed(IDR_EXTENSIONS_SECTION).AsBitmap(); 113 default_icon_ = ApplyTransforms(src); 114 } 115} 116 117SkBitmap ExtensionIconManager::ApplyTransforms(const SkBitmap& source) { 118 SkBitmap result = source; 119 120 if (result.width() != gfx::kFaviconSize || 121 result.height() != gfx::kFaviconSize) { 122 result = skia::ImageOperations::Resize( 123 result, skia::ImageOperations::RESIZE_LANCZOS3, 124 gfx::kFaviconSize, gfx::kFaviconSize); 125 } 126 127 if (monochrome_) { 128 color_utils::HSL shift = {-1, 0, 0.6}; 129 result = SkBitmapOperations::CreateHSLShiftedBitmap(result, shift); 130 } 131 132 if (!padding_.empty()) 133 result = ApplyPadding(result, padding_); 134 135 return result; 136} 137