| // 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 "extensions/browser/image_loader.h" |
| #include "extensions/common/constants.h" |
| #include "extensions/common/extension.h" |
| #include "extensions/common/extension_icon_set.h" |
| #include "extensions/common/extension_resource.h" |
| #include "extensions/common/manifest_handlers/icons_handler.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; |
| } |