1// Copyright (c) 2010 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/logging.h"
8#include "base/stl_util-inl.h"
9#include "chrome/common/extensions/extension.h"
10#include "chrome/common/extensions/extension_icon_set.h"
11#include "chrome/common/extensions/extension_resource.h"
12#include "grit/theme_resources.h"
13#include "skia/ext/image_operations.h"
14#include "ui/base/resource/resource_bundle.h"
15#include "ui/gfx/canvas_skia.h"
16#include "ui/gfx/color_utils.h"
17#include "ui/gfx/favicon_size.h"
18#include "ui/gfx/size.h"
19#include "ui/gfx/skbitmap_operations.h"
20
21namespace {
22
23// Helper function to create a new bitmap with |padding| amount of empty space
24// around the original bitmap.
25static SkBitmap ApplyPadding(const SkBitmap& source,
26                             const gfx::Insets& padding) {
27  scoped_ptr<gfx::CanvasSkia> result(
28      new gfx::CanvasSkia(source.width() + padding.width(),
29                          source.height() + padding.height(), false));
30  result->DrawBitmapInt(
31      source,
32      0, 0, source.width(), source.height(),
33      padding.left(), padding.top(), source.width(), source.height(),
34      false);
35  return result->ExtractBitmap();
36}
37
38}  // namespace
39
40ExtensionIconManager::ExtensionIconManager()
41    : ALLOW_THIS_IN_INITIALIZER_LIST(image_tracker_(this)),
42      monochrome_(false) {
43}
44
45ExtensionIconManager::~ExtensionIconManager() {
46}
47
48void ExtensionIconManager::LoadIcon(const Extension* extension) {
49  ExtensionResource icon_resource = extension->GetIconResource(
50      Extension::EXTENSION_ICON_BITTY, ExtensionIconSet::MATCH_BIGGER);
51  if (!icon_resource.extension_root().empty()) {
52    // Insert into pending_icons_ first because LoadImage can call us back
53    // synchronously if the image is already cached.
54    pending_icons_.insert(extension->id());
55    image_tracker_.LoadImage(extension,
56                             icon_resource,
57                             gfx::Size(kFaviconSize, kFaviconSize),
58                             ImageLoadingTracker::CACHE);
59  }
60}
61
62const SkBitmap& ExtensionIconManager::GetIcon(const std::string& extension_id) {
63  const SkBitmap* result = NULL;
64  if (ContainsKey(icons_, extension_id)) {
65    result = &icons_[extension_id];
66  } else {
67    EnsureDefaultIcon();
68    result = &default_icon_;
69  }
70  DCHECK(result);
71  DCHECK_EQ(kFaviconSize + padding_.width(), result->width());
72  DCHECK_EQ(kFaviconSize + padding_.height(), result->height());
73  return *result;
74}
75
76void ExtensionIconManager::RemoveIcon(const std::string& extension_id) {
77  icons_.erase(extension_id);
78  pending_icons_.erase(extension_id);
79}
80
81void ExtensionIconManager::OnImageLoaded(SkBitmap* image,
82                                         const ExtensionResource& resource,
83                                         int index) {
84  if (!image)
85    return;
86
87  const std::string extension_id = resource.extension_id();
88
89  // We may have removed the icon while waiting for it to load. In that case,
90  // do nothing.
91  if (!ContainsKey(pending_icons_, extension_id))
92    return;
93
94  pending_icons_.erase(extension_id);
95  icons_[extension_id] = ApplyTransforms(*image);
96}
97
98void ExtensionIconManager::EnsureDefaultIcon() {
99  if (default_icon_.empty()) {
100    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
101    SkBitmap* src = rb.GetBitmapNamed(IDR_EXTENSIONS_SECTION);
102    default_icon_ = ApplyTransforms(*src);
103  }
104}
105
106SkBitmap ExtensionIconManager::ApplyTransforms(const SkBitmap& source) {
107  SkBitmap result = source;
108
109  if (result.width() != kFaviconSize || result.height() != kFaviconSize) {
110    result = skia::ImageOperations::Resize(
111        result, skia::ImageOperations::RESIZE_LANCZOS3,
112        kFaviconSize, kFaviconSize);
113  }
114
115  if (monochrome_) {
116    color_utils::HSL shift = {-1, 0, 0.6};
117    result = SkBitmapOperations::CreateHSLShiftedBitmap(result, shift);
118  }
119
120  if (!padding_.empty())
121    result = ApplyPadding(result, padding_);
122
123  return result;
124}
125