| Index: trunk/src/chrome/browser/ui/webui/extensions/extension_icon_source.cc
|
| ===================================================================
|
| --- trunk/src/chrome/browser/ui/webui/extensions/extension_icon_source.cc (revision 227519)
|
| +++ trunk/src/chrome/browser/ui/webui/extensions/extension_icon_source.cc (working copy)
|
| @@ -39,6 +39,28 @@
|
|
|
| namespace extensions {
|
|
|
| +namespace {
|
| +
|
| +scoped_refptr<base::RefCountedMemory> BitmapToMemory(const SkBitmap* image) {
|
| + base::RefCountedBytes* image_bytes = new base::RefCountedBytes;
|
| + gfx::PNGCodec::EncodeBGRASkBitmap(*image, false, &image_bytes->data());
|
| + return image_bytes;
|
| +}
|
| +
|
| +SkBitmap DesaturateImage(const SkBitmap* image) {
|
| + color_utils::HSL shift = {-1, 0, 0.6};
|
| + return SkBitmapOperations::CreateHSLShiftedBitmap(*image, shift);
|
| +}
|
| +
|
| +SkBitmap* ToBitmap(const unsigned char* data, size_t size) {
|
| + SkBitmap* decoded = new SkBitmap();
|
| + bool success = gfx::PNGCodec::Decode(data, size, decoded);
|
| + DCHECK(success);
|
| + return decoded;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| ExtensionIconSource::ExtensionIconSource(Profile* profile) : profile_(profile) {
|
| }
|
|
|
| @@ -71,6 +93,18 @@
|
| return icon_url;
|
| }
|
|
|
| +// static
|
| +SkBitmap* ExtensionIconSource::LoadImageByResourceId(int resource_id) {
|
| + std::string contents = ResourceBundle::GetSharedInstance()
|
| + .GetRawDataResourceForScale(resource_id,
|
| + ui::SCALE_FACTOR_100P).as_string();
|
| +
|
| + // Convert and return it.
|
| + const unsigned char* data =
|
| + reinterpret_cast<const unsigned char*>(contents.data());
|
| + return ToBitmap(data, contents.length());
|
| +}
|
| +
|
| std::string ExtensionIconSource::GetSource() const {
|
| return chrome::kChromeUIExtensionIconHost;
|
| }
|
| @@ -90,12 +124,23 @@
|
| // the request data available for later.
|
| static int next_id = 0;
|
| if (!ParseData(path, ++next_id, callback)) {
|
| - // If the request data cannot be parsed, we will request anyway a default
|
| - // icon (not resized or desaturated).
|
| - SetData(next_id, callback, NULL, false, -1, ExtensionIconSet::MATCH_BIGGER);
|
| + // If the request data cannot be parsed, request parameters will not be
|
| + // added to |request_map_|.
|
| + // Send back the default application icon (not resized or desaturated) as
|
| + // the default response.
|
| + callback.Run(BitmapToMemory(GetDefaultAppImage()).get());
|
| + return;
|
| }
|
|
|
| - LoadExtensionImage(next_id);
|
| + ExtensionIconRequest* request = GetData(next_id);
|
| + ExtensionResource icon = IconsInfo::GetIconResource(
|
| + request->extension, request->size, request->match);
|
| +
|
| + if (icon.relative_path().empty()) {
|
| + LoadIconFailed(next_id);
|
| + } else {
|
| + LoadExtensionImage(icon, next_id);
|
| + }
|
| }
|
|
|
| ExtensionIconSource::~ExtensionIconSource() {
|
| @@ -103,23 +148,127 @@
|
| STLDeleteValues(&request_map_);
|
| }
|
|
|
| -void ExtensionIconSource::LoadExtensionImage(int request_id) {
|
| - ExtensionIconRequest* request = GetData(request_id);
|
| - ImageLoader::Get(profile_)->LoadExtensionIconAsync(
|
| - request->extension,
|
| - request->size,
|
| - request->match,
|
| - request->grayscale,
|
| - base::Bind(&ExtensionIconSource::OnIconLoaded, AsWeakPtr(), request_id));
|
| +const SkBitmap* ExtensionIconSource::GetDefaultAppImage() {
|
| + if (!default_app_data_.get())
|
| + default_app_data_.reset(LoadImageByResourceId(IDR_APP_DEFAULT_ICON));
|
| +
|
| + return default_app_data_.get();
|
| }
|
|
|
| -void ExtensionIconSource::OnIconLoaded(int request_id, const gfx::Image& image)
|
| -{
|
| +const SkBitmap* ExtensionIconSource::GetDefaultExtensionImage() {
|
| + if (!default_extension_data_.get()) {
|
| + default_extension_data_.reset(
|
| + LoadImageByResourceId(IDR_EXTENSION_DEFAULT_ICON));
|
| + }
|
| +
|
| + return default_extension_data_.get();
|
| +}
|
| +
|
| +void ExtensionIconSource::FinalizeImage(const SkBitmap* image,
|
| + int request_id) {
|
| + SkBitmap bitmap;
|
| ExtensionIconRequest* request = GetData(request_id);
|
| - request->callback.Run(ImageLoader::BitmapToMemory(image.ToSkBitmap()).get());
|
| + if (request->grayscale)
|
| + bitmap = DesaturateImage(image);
|
| + else
|
| + bitmap = *image;
|
| +
|
| + request->callback.Run(BitmapToMemory(&bitmap).get());
|
| ClearData(request_id);
|
| }
|
|
|
| +void ExtensionIconSource::LoadDefaultImage(int request_id) {
|
| + ExtensionIconRequest* request = GetData(request_id);
|
| + const SkBitmap* default_image = NULL;
|
| +
|
| + if (request->extension->is_app())
|
| + default_image = GetDefaultAppImage();
|
| + else
|
| + default_image = GetDefaultExtensionImage();
|
| +
|
| + SkBitmap resized_image(skia::ImageOperations::Resize(
|
| + *default_image, skia::ImageOperations::RESIZE_LANCZOS3,
|
| + request->size, request->size));
|
| +
|
| + // There are cases where Resize returns an empty bitmap, for example if you
|
| + // ask for an image too large. In this case it is better to return the default
|
| + // image than returning nothing at all.
|
| + if (resized_image.empty())
|
| + resized_image = *default_image;
|
| +
|
| + FinalizeImage(&resized_image, request_id);
|
| +}
|
| +
|
| +void ExtensionIconSource::LoadExtensionImage(const ExtensionResource& icon,
|
| + int request_id) {
|
| + ExtensionIconRequest* request = GetData(request_id);
|
| + ImageLoader::Get(profile_)->LoadImageAsync(
|
| + request->extension, icon,
|
| + gfx::Size(request->size, request->size),
|
| + base::Bind(&ExtensionIconSource::OnImageLoaded, AsWeakPtr(), request_id));
|
| +}
|
| +
|
| +void ExtensionIconSource::LoadFaviconImage(int request_id) {
|
| + FaviconService* favicon_service =
|
| + FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS);
|
| + // Fall back to the default icons if the service isn't available.
|
| + if (favicon_service == NULL) {
|
| + LoadDefaultImage(request_id);
|
| + return;
|
| + }
|
| +
|
| + GURL favicon_url =
|
| + AppLaunchInfo::GetFullLaunchURL(GetData(request_id)->extension);
|
| + favicon_service->GetRawFaviconForURL(
|
| + FaviconService::FaviconForURLParams(
|
| + profile_, favicon_url, chrome::FAVICON, gfx::kFaviconSize),
|
| + ui::SCALE_FACTOR_100P,
|
| + base::Bind(&ExtensionIconSource::OnFaviconDataAvailable,
|
| + base::Unretained(this), request_id),
|
| + &cancelable_task_tracker_);
|
| +}
|
| +
|
| +void ExtensionIconSource::OnFaviconDataAvailable(
|
| + int request_id,
|
| + const chrome::FaviconBitmapResult& bitmap_result) {
|
| + ExtensionIconRequest* request = GetData(request_id);
|
| +
|
| + // Fallback to the default icon if there wasn't a favicon.
|
| + if (!bitmap_result.is_valid()) {
|
| + LoadDefaultImage(request_id);
|
| + return;
|
| + }
|
| +
|
| + if (!request->grayscale) {
|
| + // If we don't need a grayscale image, then we can bypass FinalizeImage
|
| + // to avoid unnecessary conversions.
|
| + request->callback.Run(bitmap_result.bitmap_data.get());
|
| + ClearData(request_id);
|
| + } else {
|
| + FinalizeImage(ToBitmap(bitmap_result.bitmap_data->front(),
|
| + bitmap_result.bitmap_data->size()), request_id);
|
| + }
|
| +}
|
| +
|
| +void ExtensionIconSource::OnImageLoaded(int request_id,
|
| + const gfx::Image& image) {
|
| + if (image.IsEmpty())
|
| + LoadIconFailed(request_id);
|
| + else
|
| + FinalizeImage(image.ToSkBitmap(), request_id);
|
| +}
|
| +
|
| +void ExtensionIconSource::LoadIconFailed(int request_id) {
|
| + ExtensionIconRequest* request = GetData(request_id);
|
| + ExtensionResource icon = IconsInfo::GetIconResource(
|
| + request->extension, request->size, request->match);
|
| +
|
| + if (request->size == extension_misc::EXTENSION_ICON_BITTY)
|
| + LoadFaviconImage(request_id);
|
| + else
|
| + LoadDefaultImage(request_id);
|
| +}
|
| +
|
| bool ExtensionIconSource::ParseData(
|
| const std::string& path,
|
| int request_id,
|
|
|