1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_icon_manager.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/stl_util-inl.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/common/extensions/extension_icon_set.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension_resource.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "skia/ext/image_operations.h"
1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h"
1572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas_skia.h"
1672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/color_utils.h"
1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/favicon_size.h"
1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/size.h"
1972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/skbitmap_operations.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricknamespace {
223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Helper function to create a new bitmap with |padding| amount of empty space
243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// around the original bitmap.
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic SkBitmap ApplyPadding(const SkBitmap& source,
263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                             const gfx::Insets& padding) {
273345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  scoped_ptr<gfx::CanvasSkia> result(
283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      new gfx::CanvasSkia(source.width() + padding.width(),
293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                          source.height() + padding.height(), false));
303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  result->DrawBitmapInt(
313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      source,
323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      0, 0, source.width(), source.height(),
333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      padding.left(), padding.top(), source.width(), source.height(),
343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      false);
353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return result->ExtractBitmap();
363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}  // namespace
393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochExtensionIconManager::ExtensionIconManager()
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : ALLOW_THIS_IN_INITIALIZER_LIST(image_tracker_(this)),
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      monochrome_(false) {
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
453345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickExtensionIconManager::~ExtensionIconManager() {
463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
48513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid ExtensionIconManager::LoadIcon(const Extension* extension) {
493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ExtensionResource icon_resource = extension->GetIconResource(
503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      Extension::EXTENSION_ICON_BITTY, ExtensionIconSet::MATCH_BIGGER);
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!icon_resource.extension_root().empty()) {
523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Insert into pending_icons_ first because LoadImage can call us back
533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // synchronously if the image is already cached.
543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    pending_icons_.insert(extension->id());
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    image_tracker_.LoadImage(extension,
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             icon_resource,
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                             gfx::Size(kFaviconSize, kFaviconSize),
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             ImageLoadingTracker::CACHE);
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkBitmap& ExtensionIconManager::GetIcon(const std::string& extension_id) {
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const SkBitmap* result = NULL;
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (ContainsKey(icons_, extension_id)) {
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result = &icons_[extension_id];
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    EnsureDefaultIcon();
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result = &default_icon_;
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(result);
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(kFaviconSize + padding_.width(), result->width());
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK_EQ(kFaviconSize + padding_.height(), result->height());
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return *result;
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionIconManager::RemoveIcon(const std::string& extension_id) {
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  icons_.erase(extension_id);
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pending_icons_.erase(extension_id);
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionIconManager::OnImageLoaded(SkBitmap* image,
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                         const ExtensionResource& resource,
83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         int index) {
84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!image)
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  const std::string extension_id = resource.extension_id();
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We may have removed the icon while waiting for it to load. In that case,
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // do nothing.
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!ContainsKey(pending_icons_, extension_id))
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  pending_icons_.erase(extension_id);
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  icons_[extension_id] = ApplyTransforms(*image);
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionIconManager::EnsureDefaultIcon() {
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (default_icon_.empty()) {
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    SkBitmap* src = rb.GetBitmapNamed(IDR_EXTENSIONS_SECTION);
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    default_icon_ = ApplyTransforms(*src);
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSkBitmap ExtensionIconManager::ApplyTransforms(const SkBitmap& source) {
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SkBitmap result = source;
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (result.width() != kFaviconSize || result.height() != kFaviconSize) {
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result = skia::ImageOperations::Resize(
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        result, skia::ImageOperations::RESIZE_LANCZOS3,
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        kFaviconSize, kFaviconSize);
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (monochrome_) {
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    color_utils::HSL shift = {-1, 0, 0.6};
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    result = SkBitmapOperations::CreateHSLShiftedBitmap(result, shift);
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!padding_.empty())
1213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    result = ApplyPadding(result, padding_);
1223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return result;
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
125