// Copyright (c) 2012 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/bind.h" #include "base/logging.h" #include "base/stl_util.h" #include "chrome/browser/extensions/image_loader.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension_icon_set.h" #include "chrome/common/extensions/manifest_handlers/icons_handler.h" #include "extensions/common/extension.h" #include "extensions/common/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.h" #include "ui/gfx/color_utils.h" #include "ui/gfx/favicon_size.h" #include "ui/gfx/image/image.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::Canvas> result( new gfx::Canvas(gfx::Size(source.width() + padding.width(), source.height() + padding.height()), 1.0f, false)); result->DrawImageInt( gfx::ImageSkia::CreateFrom1xBitmap(source), 0, 0, source.width(), source.height(), padding.left(), padding.top(), source.width(), source.height(), false); return result->ExtractImageRep().sk_bitmap(); } } // namespace ExtensionIconManager::ExtensionIconManager() : monochrome_(false), weak_ptr_factory_(this) { } ExtensionIconManager::~ExtensionIconManager() { } void ExtensionIconManager::LoadIcon(content::BrowserContext* context, const extensions::Extension* extension) { extensions::ExtensionResource icon_resource = extensions::IconsInfo::GetIconResource( extension, extension_misc::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()); extensions::ImageLoader* loader = extensions::ImageLoader::Get(context); loader->LoadImageAsync(extension, icon_resource, gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize), base::Bind( &ExtensionIconManager::OnImageLoaded, weak_ptr_factory_.GetWeakPtr(), extension->id())); } } 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(gfx::kFaviconSize + padding_.width(), result->width()); DCHECK_EQ(gfx::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(const std::string& extension_id, const gfx::Image& image) { if (image.IsEmpty()) return; // 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.ToSkBitmap()); } void ExtensionIconManager::EnsureDefaultIcon() { if (default_icon_.empty()) { ResourceBundle& rb = ResourceBundle::GetSharedInstance(); SkBitmap src = rb.GetImageNamed(IDR_EXTENSIONS_SECTION).AsBitmap(); default_icon_ = ApplyTransforms(src); } } SkBitmap ExtensionIconManager::ApplyTransforms(const SkBitmap& source) { SkBitmap result = source; if (result.width() != gfx::kFaviconSize || result.height() != gfx::kFaviconSize) { result = skia::ImageOperations::Resize( result, skia::ImageOperations::RESIZE_LANCZOS3, gfx::kFaviconSize, gfx::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; }