Index: chrome/browser/extensions/api/developer_private/extension_info_generator.cc |
diff --git a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc |
index 9ac1c437bb94dda7831f2e83e532ffccd3081125..fd91759ec21c43cfb965ff5b1b490047d011d50b 100644 |
--- a/chrome/browser/extensions/api/developer_private/extension_info_generator.cc |
+++ b/chrome/browser/extensions/api/developer_private/extension_info_generator.cc |
@@ -4,6 +4,7 @@ |
#include "chrome/browser/extensions/api/developer_private/extension_info_generator.h" |
+#include "base/base64.h" |
#include "base/strings/utf_string_conversions.h" |
#include "chrome/browser/extensions/api/developer_private/inspectable_views_finder.h" |
#include "chrome/browser/extensions/api/extension_action/extension_action_api.h" |
@@ -22,17 +23,25 @@ |
#include "extensions/browser/extension_prefs.h" |
#include "extensions/browser/extension_registry.h" |
#include "extensions/browser/extension_system.h" |
+#include "extensions/browser/image_loader.h" |
#include "extensions/browser/warning_service.h" |
#include "extensions/common/extension_set.h" |
#include "extensions/common/feature_switch.h" |
#include "extensions/common/install_warning.h" |
#include "extensions/common/manifest.h" |
#include "extensions/common/manifest_handlers/background_info.h" |
+#include "extensions/common/manifest_handlers/icons_handler.h" |
#include "extensions/common/manifest_handlers/offline_enabled_info.h" |
#include "extensions/common/manifest_handlers/options_page_info.h" |
#include "extensions/common/manifest_url_handlers.h" |
#include "extensions/common/permissions/permissions_data.h" |
+#include "extensions/grit/extensions_browser_resources.h" |
#include "ui/base/l10n/l10n_util.h" |
+#include "ui/base/resource/resource_bundle.h" |
+#include "ui/gfx/codec/png_codec.h" |
+#include "ui/gfx/color_utils.h" |
+#include "ui/gfx/image/image.h" |
+#include "ui/gfx/skbitmap_operations.h" |
namespace extensions { |
@@ -142,15 +151,83 @@ ExtensionInfoGenerator::ExtensionInfoGenerator( |
extension_prefs_(ExtensionPrefs::Get(browser_context)), |
extension_action_api_(ExtensionActionAPI::Get(browser_context)), |
warning_service_(WarningService::Get(browser_context)), |
- error_console_(ErrorConsole::Get(browser_context)) { |
+ error_console_(ErrorConsole::Get(browser_context)), |
+ image_loader_(ImageLoader::Get(browser_context)), |
+ pending_image_loads_(0u), |
+ weak_factory_(this) { |
} |
ExtensionInfoGenerator::~ExtensionInfoGenerator() { |
} |
-scoped_ptr<developer::ExtensionInfo> |
-ExtensionInfoGenerator::CreateExtensionInfo(const Extension& extension, |
- developer::ExtensionState state) { |
+void ExtensionInfoGenerator::CreateExtensionInfo( |
+ const std::string& id, |
+ const ExtensionInfosCallback& callback) { |
+ DCHECK(callback_.is_null() && list_.empty()) << |
+ "Only a single generation can be running at a time!"; |
+ ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); |
+ |
+ developer::ExtensionState state = developer::EXTENSION_STATE_NONE; |
+ const Extension* ext = nullptr; |
+ if ((ext = registry->enabled_extensions().GetByID(id)) != nullptr) |
+ state = developer::EXTENSION_STATE_ENABLED; |
+ else if ((ext = registry->disabled_extensions().GetByID(id)) != nullptr) |
+ state = developer::EXTENSION_STATE_DISABLED; |
+ else if ((ext = registry->terminated_extensions().GetByID(id)) != nullptr) |
+ state = developer::EXTENSION_STATE_TERMINATED; |
+ |
+ if (ext && ui_util::ShouldDisplayInExtensionSettings(ext, browser_context_)) |
+ CreateExtensionInfoHelper(*ext, state); |
+ |
+ if (pending_image_loads_ == 0) { |
+ // Don't call the callback re-entrantly. |
+ base::MessageLoop::current()->PostTask(FROM_HERE, |
+ base::Bind(callback, list_)); |
+ list_.clear(); |
+ } else { |
+ callback_ = callback; |
+ } |
+} |
+ |
+void ExtensionInfoGenerator::CreateExtensionsInfo( |
+ bool include_disabled, |
+ bool include_terminated, |
+ const ExtensionInfosCallback& callback) { |
+ auto add_to_list = [this](const ExtensionSet& extensions, |
+ developer::ExtensionState state) { |
+ for (const scoped_refptr<const Extension>& extension : extensions) { |
+ if (ui_util::ShouldDisplayInExtensionSettings(extension.get(), |
+ browser_context_)) { |
+ CreateExtensionInfoHelper(*extension, state); |
+ } |
+ } |
+ }; |
+ |
+ ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); |
+ add_to_list(registry->enabled_extensions(), |
+ developer::EXTENSION_STATE_ENABLED); |
+ if (include_disabled) { |
+ add_to_list(registry->disabled_extensions(), |
+ developer::EXTENSION_STATE_DISABLED); |
+ } |
+ if (include_terminated) { |
+ add_to_list(registry->terminated_extensions(), |
+ developer::EXTENSION_STATE_TERMINATED); |
+ } |
+ |
+ if (pending_image_loads_ == 0) { |
+ // Don't call the callback re-entrantly. |
+ base::MessageLoop::current()->PostTask(FROM_HERE, |
+ base::Bind(callback, list_)); |
+ list_.clear(); |
+ } else { |
+ callback_ = callback; |
+ } |
+} |
+ |
+void ExtensionInfoGenerator::CreateExtensionInfoHelper( |
+ const Extension& extension, |
+ developer::ExtensionState state) { |
scoped_ptr<developer::ExtensionInfo> info(new developer::ExtensionInfo()); |
// Don't consider the button hidden with the redesign, because "hidden" |
@@ -217,17 +294,6 @@ ExtensionInfoGenerator::CreateExtensionInfo(const Extension& extension, |
info->home_page.url = ManifestURL::GetHomepageURL(&extension).spec(); |
info->home_page.specified = ManifestURL::SpecifiedHomepageURL(&extension); |
- bool is_enabled = state == developer::EXTENSION_STATE_ENABLED; |
- |
- // TODO(devlin): This won't work with apps (CORS). We should convert to data |
- // urls. |
- info->icon_url = |
- ExtensionIconSource::GetIconURL(&extension, |
- extension_misc::EXTENSION_ICON_MEDIUM, |
- ExtensionIconSet::MATCH_BIGGER, |
- !is_enabled, |
- nullptr).spec(); |
- |
info->id = extension.id(); |
// Incognito access. |
@@ -357,68 +423,98 @@ ExtensionInfoGenerator::CreateExtensionInfo(const Extension& extension, |
info->version = extension.GetVersionForDisplay(); |
+ bool is_enabled = state == developer::EXTENSION_STATE_ENABLED; |
if (state != developer::EXTENSION_STATE_TERMINATED) { |
info->views = InspectableViewsFinder(profile). |
GetViewsForExtension(extension, is_enabled); |
} |
- return info.Pass(); |
-} |
-scoped_ptr<api::developer_private::ExtensionInfo> |
-ExtensionInfoGenerator::CreateExtensionInfo(const std::string& id) { |
- ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); |
- |
- const Extension* enabled = registry->enabled_extensions().GetByID(id); |
- if (enabled && |
- ui_util::ShouldDisplayInExtensionSettings(enabled, browser_context_)) { |
- return CreateExtensionInfo(*enabled, developer::EXTENSION_STATE_ENABLED); |
+ // The icon. |
+ ExtensionResource icon = |
+ IconsInfo::GetIconResource(&extension, |
+ extension_misc::EXTENSION_ICON_MEDIUM, |
+ ExtensionIconSet::MATCH_BIGGER); |
+ if (icon.empty()) { |
+ info->icon_url = GetDefaultIconUrl(extension.is_app(), !is_enabled); |
+ list_.push_back(make_linked_ptr(info.release())); |
+ } else { |
+ ++pending_image_loads_; |
+ // Max size of 128x128 is a random guess at a nice balance between being |
+ // overly eager to resize and sending across gigantic data urls. (The icon |
+ // used by the url is 48x48). |
+ gfx::Size max_size(128, 128); |
+ image_loader_->LoadImageAsync( |
+ &extension, |
+ icon, |
+ max_size, |
+ base::Bind(&ExtensionInfoGenerator::OnImageLoaded, |
+ weak_factory_.GetWeakPtr(), |
+ base::Passed(info.Pass()))); |
} |
+} |
- const Extension* disabled = registry->disabled_extensions().GetByID(id); |
- if (disabled && |
- ui_util::ShouldDisplayInExtensionSettings(disabled, browser_context_)) { |
- return CreateExtensionInfo(*disabled, developer::EXTENSION_STATE_DISABLED); |
+const std::string& ExtensionInfoGenerator::GetDefaultIconUrl( |
+ bool is_app, |
+ bool is_greyscale) { |
+ std::string* str; |
+ if (is_app) { |
+ str = is_greyscale ? &default_disabled_app_icon_url_ : |
+ &default_app_icon_url_; |
+ } else { |
+ str = is_greyscale ? &default_disabled_extension_icon_url_ : |
+ &default_extension_icon_url_; |
} |
- const Extension* terminated = registry->terminated_extensions().GetByID(id); |
- if (terminated && |
- ui_util::ShouldDisplayInExtensionSettings(terminated, browser_context_)) { |
- return CreateExtensionInfo(*terminated, |
- developer::EXTENSION_STATE_TERMINATED); |
+ if (str->empty()) { |
+ *str = GetIconUrlFromImage( |
+ ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
+ is_app ? IDR_APP_DEFAULT_ICON : IDR_EXTENSION_DEFAULT_ICON), |
+ is_greyscale); |
} |
- return scoped_ptr<api::developer_private::ExtensionInfo>(); |
+ return *str; |
} |
-ExtensionInfoGenerator::ExtensionInfoList |
-ExtensionInfoGenerator::CreateExtensionsInfo(bool include_disabled, |
- bool include_terminated) { |
- std::vector<linked_ptr<developer::ExtensionInfo>> list; |
- auto add_to_list = [this, &list](const ExtensionSet& extensions, |
- developer::ExtensionState state) { |
- for (const scoped_refptr<const Extension>& extension : extensions) { |
- if (ui_util::ShouldDisplayInExtensionSettings(extension.get(), |
- browser_context_)) { |
- scoped_ptr<developer::ExtensionInfo> info = |
- CreateExtensionInfo(*extension, state); |
- list.push_back(make_linked_ptr(info.release())); |
- } |
- } |
- }; |
- |
- ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_); |
- add_to_list(registry->enabled_extensions(), |
- developer::EXTENSION_STATE_ENABLED); |
- if (include_disabled) { |
- add_to_list(registry->disabled_extensions(), |
- developer::EXTENSION_STATE_DISABLED); |
- } |
- if (include_terminated) { |
- add_to_list(registry->terminated_extensions(), |
- developer::EXTENSION_STATE_TERMINATED); |
+std::string ExtensionInfoGenerator::GetIconUrlFromImage( |
+ const gfx::Image& image, |
+ bool should_greyscale) { |
+ scoped_refptr<base::RefCountedMemory> data; |
+ if (should_greyscale) { |
+ color_utils::HSL shift = {-1, 0, 0.6}; |
+ SkBitmap bitmap = |
+ SkBitmapOperations::CreateHSLShiftedBitmap(*image.ToSkBitmap(), shift); |
+ scoped_refptr<base::RefCountedBytes> image_bytes( |
+ new base::RefCountedBytes()); |
+ gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &image_bytes->data()); |
+ data = image_bytes; |
+ } else { |
+ data = image.As1xPNGBytes(); |
} |
- return list; |
+ std::string base_64; |
+ base::Base64Encode(std::string(data->front_as<char>(), data->size()), |
+ &base_64); |
+ const char kDataUrlPrefix[] = "data:image/png;base64,"; |
+ return GURL(kDataUrlPrefix + base_64).spec(); |
+} |
+ |
+void ExtensionInfoGenerator::OnImageLoaded( |
+ scoped_ptr<developer::ExtensionInfo> info, |
+ const gfx::Image& icon) { |
+ info->icon_url = GetIconUrlFromImage( |
+ icon, info->state != developer::EXTENSION_STATE_ENABLED); |
+ list_.push_back(make_linked_ptr(info.release())); |
+ |
+ --pending_image_loads_; |
+ |
+ if (pending_image_loads_ == 0) { // All done! |
+ // We assign to a temporary and Reset() so that at the end of the method, |
+ // any stored refs are destroyed. |
+ ExtensionInfosCallback callback = callback_; |
+ callback_.Reset(); |
+ callback.Run(list_); |
+ list_.clear(); |
+ } |
} |
} // namespace extensions |