// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/extension_icon_manager.h"
#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/extension_resource.h"
#include "grit/theme_resources.h"
#include "skia/ext/image_operations.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/canvas_skia.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/favicon_size.h"
#include "ui/gfx/size.h"
#include "ui/gfx/skbitmap_operations.h"
namespace {
// Helper function to create a new bitmap with |padding| amount of empty space
// around the original bitmap.
static SkBitmap ApplyPadding(const SkBitmap& source,
const gfx::Insets& padding) {
scoped_ptr<gfx::CanvasSkia> result(
new gfx::CanvasSkia(source.width() + padding.width(),
source.height() + padding.height(), false));
result->DrawBitmapInt(
source,
0, 0, source.width(), source.height(),
padding.left(), padding.top(), source.width(), source.height(),
false);
return result->ExtractBitmap();
}
} // namespace
ExtensionIconManager::ExtensionIconManager()
: ALLOW_THIS_IN_INITIALIZER_LIST(image_tracker_(this)),
monochrome_(false) {
}
ExtensionIconManager::~ExtensionIconManager() {
}
void ExtensionIconManager::LoadIcon(const Extension* extension) {
ExtensionResource icon_resource = extension->GetIconResource(
Extension::EXTENSION_ICON_BITTY, ExtensionIconSet::MATCH_BIGGER);
if (!icon_resource.extension_root().empty()) {
// Insert into pending_icons_ first because LoadImage can call us back
// synchronously if the image is already cached.
pending_icons_.insert(extension->id());
image_tracker_.LoadImage(extension,
icon_resource,
gfx::Size(kFaviconSize, kFaviconSize),
ImageLoadingTracker::CACHE);
}
}
const SkBitmap& ExtensionIconManager::GetIcon(const std::string& extension_id) {
const SkBitmap* result = NULL;
if (ContainsKey(icons_, extension_id)) {
result = &icons_[extension_id];
} else {
EnsureDefaultIcon();
result = &default_icon_;
}
DCHECK(result);
DCHECK_EQ(kFaviconSize + padding_.width(), result->width());
DCHECK_EQ(kFaviconSize + padding_.height(), result->height());
return *result;
}
void ExtensionIconManager::RemoveIcon(const std::string& extension_id) {
icons_.erase(extension_id);
pending_icons_.erase(extension_id);
}
void ExtensionIconManager::OnImageLoaded(SkBitmap* image,
const ExtensionResource& resource,
int index) {
if (!image)
return;
const std::string extension_id = resource.extension_id();
// We may have removed the icon while waiting for it to load. In that case,
// do nothing.
if (!ContainsKey(pending_icons_, extension_id))
return;
pending_icons_.erase(extension_id);
icons_[extension_id] = ApplyTransforms(*image);
}
void ExtensionIconManager::EnsureDefaultIcon() {
if (default_icon_.empty()) {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
SkBitmap* src = rb.GetBitmapNamed(IDR_EXTENSIONS_SECTION);
default_icon_ = ApplyTransforms(*src);
}
}
SkBitmap ExtensionIconManager::ApplyTransforms(const SkBitmap& source) {
SkBitmap result = source;
if (result.width() != kFaviconSize || result.height() != kFaviconSize) {
result = skia::ImageOperations::Resize(
result, skia::ImageOperations::RESIZE_LANCZOS3,
kFaviconSize, kFaviconSize);
}
if (monochrome_) {
color_utils::HSL shift = {-1, 0, 0.6};
result = SkBitmapOperations::CreateHSLShiftedBitmap(result, shift);
}
if (!padding_.empty())
result = ApplyPadding(result, padding_);
return result;
}