15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_icon_manager.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h" 106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "extensions/browser/image_loader.h" 11c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/constants.h" 12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h" 13c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/extension_icon_set.h" 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/extension_resource.h" 15c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/manifest_handlers/icons_handler.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "skia/ext/image_operations.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/color_utils.h" 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/favicon_size.h" 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image.h" 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/size.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/skbitmap_operations.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper function to create a new bitmap with |padding| amount of empty space 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// around the original bitmap. 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static SkBitmap ApplyPadding(const SkBitmap& source, 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Insets& padding) { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<gfx::Canvas> result( 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new gfx::Canvas(gfx::Size(source.width() + padding.width(), 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) source.height() + padding.height()), 3568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 1.0f, 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false)); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result->DrawImageInt( 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::ImageSkia::CreateFrom1xBitmap(source), 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 0, source.width(), source.height(), 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) padding.left(), padding.top(), source.width(), source.height(), 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) false); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result->ExtractImageRep().sk_bitmap(); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionIconManager::ExtensionIconManager() 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : monochrome_(false), 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) weak_ptr_factory_(this) { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionIconManager::~ExtensionIconManager() { 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void ExtensionIconManager::LoadIcon(content::BrowserContext* context, 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const extensions::Extension* extension) { 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extensions::ExtensionResource icon_resource = 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extensions::IconsInfo::GetIconResource( 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extension, 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extension_misc::EXTENSION_ICON_BITTY, 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ExtensionIconSet::MATCH_BIGGER); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!icon_resource.extension_root().empty()) { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Insert into pending_icons_ first because LoadImage can call us back 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // synchronously if the image is already cached. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_icons_.insert(extension->id()); 661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) extensions::ImageLoader* loader = extensions::ImageLoader::Get(context); 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) loader->LoadImageAsync(extension, icon_resource, 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize), 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind( 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) &ExtensionIconManager::OnImageLoaded, 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) extension->id())); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const SkBitmap& ExtensionIconManager::GetIcon(const std::string& extension_id) { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkBitmap* result = NULL; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (ContainsKey(icons_, extension_id)) { 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = &icons_[extension_id]; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureDefaultIcon(); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = &default_icon_; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(result); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(gfx::kFaviconSize + padding_.width(), result->width()); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(gfx::kFaviconSize + padding_.height(), result->height()); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return *result; 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionIconManager::RemoveIcon(const std::string& extension_id) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icons_.erase(extension_id); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_icons_.erase(extension_id); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionIconManager::OnImageLoaded(const std::string& extension_id, 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const gfx::Image& image) { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (image.IsEmpty()) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We may have removed the icon while waiting for it to load. In that case, 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // do nothing. 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ContainsKey(pending_icons_, extension_id)) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_icons_.erase(extension_id); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) icons_[extension_id] = ApplyTransforms(*image.ToSkBitmap()); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionIconManager::EnsureDefaultIcon() { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (default_icon_.empty()) { 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkBitmap src = rb.GetImageNamed(IDR_EXTENSIONS_SECTION).AsBitmap(); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default_icon_ = ApplyTransforms(src); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkBitmap ExtensionIconManager::ApplyTransforms(const SkBitmap& source) { 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkBitmap result = source; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result.width() != gfx::kFaviconSize || 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.height() != gfx::kFaviconSize) { 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = skia::ImageOperations::Resize( 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result, skia::ImageOperations::RESIZE_LANCZOS3, 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::kFaviconSize, gfx::kFaviconSize); 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (monochrome_) { 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) color_utils::HSL shift = {-1, 0, 0.6}; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = SkBitmapOperations::CreateHSLShiftedBitmap(result, shift); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!padding_.empty()) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = ApplyPadding(result, padding_); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 137