Home | History | Annotate | Download | only in extensions
      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 "chrome/browser/extensions/image_loader.h"
     11 #include "chrome/common/extensions/extension_constants.h"
     12 #include "chrome/common/extensions/extension_icon_set.h"
     13 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
     14 #include "extensions/common/extension.h"
     15 #include "extensions/common/extension_resource.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 
     26 namespace {
     27 
     28 // Helper function to create a new bitmap with |padding| amount of empty space
     29 // around the original bitmap.
     30 static 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 
     47 ExtensionIconManager::ExtensionIconManager()
     48     : monochrome_(false),
     49       weak_ptr_factory_(this)  {
     50 }
     51 
     52 ExtensionIconManager::~ExtensionIconManager() {
     53 }
     54 
     55 void 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 
     76 const 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 
     90 void ExtensionIconManager::RemoveIcon(const std::string& extension_id) {
     91   icons_.erase(extension_id);
     92   pending_icons_.erase(extension_id);
     93 }
     94 
     95 void 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 
    109 void 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 
    117 SkBitmap 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