summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/background/background_application_list_model.cc21
-rw-r--r--chrome/browser/extensions/extension_icon_image_unittest.cc46
-rw-r--r--chrome/browser/extensions/extension_install_prompt.cc20
-rw-r--r--chrome/browser/extensions/extension_install_prompt.h20
-rw-r--r--chrome/browser/extensions/extension_protocols.cc4
-rw-r--r--chrome/browser/extensions/extension_system.h5
-rw-r--r--chrome/browser/extensions/extension_web_ui.cc183
-rw-r--r--chrome/browser/extensions/image_loader.cc327
-rw-r--r--chrome/browser/extensions/image_loader.h113
-rw-r--r--chrome/browser/extensions/image_loader_factory.cc50
-rw-r--r--chrome/browser/extensions/image_loader_factory.h43
-rw-r--r--chrome/browser/extensions/image_loader_unittest.cc252
-rw-r--r--chrome/browser/extensions/image_loading_tracker.cc64
-rw-r--r--chrome/browser/extensions/image_loading_tracker.h8
-rw-r--r--chrome/browser/extensions/image_loading_tracker_unittest.cc21
-rw-r--r--chrome/browser/extensions/navigation_observer.h1
-rw-r--r--chrome/browser/media/media_stream_capture_indicator.cc43
-rw-r--r--chrome/browser/media/media_stream_capture_indicator.h21
-rw-r--r--chrome/browser/ui/webui/extensions/extension_icon_source.cc22
-rw-r--r--chrome/browser/ui/webui/extensions/extension_icon_source.h15
-rw-r--r--chrome/chrome_browser_extensions.gypi4
-rw-r--r--chrome/chrome_tests_unit.gypi1
22 files changed, 959 insertions, 325 deletions
diff --git a/chrome/browser/background/background_application_list_model.cc b/chrome/browser/background/background_application_list_model.cc
index e0c6010..3b2faf0 100644
--- a/chrome/browser/background/background_application_list_model.cc
+++ b/chrome/browser/background/background_application_list_model.cc
@@ -16,7 +16,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/image_loading_tracker.h"
+#include "chrome/browser/extensions/image_loader.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
@@ -60,7 +60,7 @@ bool ExtensionNameComparator::operator()(const Extension* x,
// Background application representation, private to the
// BackgroundApplicationListModel class.
class BackgroundApplicationListModel::Application
- : public ImageLoadingTracker::Observer {
+ : public base::SupportsWeakPtr<Application> {
public:
Application(BackgroundApplicationListModel* model,
const Extension* an_extension);
@@ -68,9 +68,7 @@ class BackgroundApplicationListModel::Application
virtual ~Application();
// Invoked when a request icon is available.
- virtual void OnImageLoaded(const gfx::Image& image,
- const std::string& extension_id,
- int index) OVERRIDE;
+ void OnImageLoaded(const gfx::Image& image);
// Uses the FILE thread to request this extension's icon, sized
// appropriately.
@@ -79,7 +77,6 @@ class BackgroundApplicationListModel::Application
const Extension* extension_;
scoped_ptr<gfx::ImageSkia> icon_;
BackgroundApplicationListModel* model_;
- ImageLoadingTracker tracker_;
};
namespace {
@@ -141,14 +138,11 @@ BackgroundApplicationListModel::Application::Application(
const Extension* extension)
: extension_(extension),
icon_(NULL),
- model_(model),
- ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) {
+ model_(model) {
}
void BackgroundApplicationListModel::Application::OnImageLoaded(
- const gfx::Image& image,
- const std::string& extension_id,
- int index) {
+ const gfx::Image& image) {
if (image.IsEmpty())
return;
icon_.reset(image.CopyImageSkia());
@@ -159,8 +153,9 @@ void BackgroundApplicationListModel::Application::RequestIcon(
extension_misc::ExtensionIcons size) {
ExtensionResource resource = extension_->GetIconResource(
size, ExtensionIconSet::MATCH_BIGGER);
- tracker_.LoadImage(extension_, resource, gfx::Size(size, size),
- ImageLoadingTracker::CACHE);
+ extensions::ImageLoader::Get(model_->profile_)->LoadImageAsync(
+ extension_, resource, gfx::Size(size, size),
+ base::Bind(&Application::OnImageLoaded, AsWeakPtr()));
}
BackgroundApplicationListModel::~BackgroundApplicationListModel() {
diff --git a/chrome/browser/extensions/extension_icon_image_unittest.cc b/chrome/browser/extensions/extension_icon_image_unittest.cc
index 8ca3747..e293ed8 100644
--- a/chrome/browser/extensions/extension_icon_image_unittest.cc
+++ b/chrome/browser/extensions/extension_icon_image_unittest.cc
@@ -7,7 +7,7 @@
#include "base/json/json_file_value_serializer.h"
#include "base/message_loop.h"
#include "base/path_service.h"
-#include "chrome/browser/extensions/image_loading_tracker.h"
+#include "chrome/browser/extensions/image_loader.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
@@ -65,20 +65,16 @@ class MockImageSkiaSource : public gfx::ImageSkiaSource {
};
// Helper class for synchronously loading extension image resource.
-class TestImageLoader : public ImageLoadingTracker::Observer {
+class TestImageLoader {
public:
explicit TestImageLoader(const Extension* extension)
: extension_(extension),
waiting_(false),
- image_loaded_(false),
- ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) {
+ image_loaded_(false) {
}
virtual ~TestImageLoader() {}
- // ImageLoadingTracker::Observer override.
- virtual void OnImageLoaded(const gfx::Image& image,
- const std::string& extension_id,
- int index) OVERRIDE {
+ void OnImageLoaded(const gfx::Image& image) {
image_ = image;
image_loaded_ = true;
if (waiting_)
@@ -86,14 +82,13 @@ class TestImageLoader : public ImageLoadingTracker::Observer {
}
SkBitmap LoadBitmap(const std::string& path,
- int size,
- ImageLoadingTracker::CacheParam cache_param) {
+ int size) {
image_loaded_ = false;
- tracker_.LoadImage(extension_,
- extension_->GetResource(path),
- gfx::Size(size, size),
- cache_param);
+ image_loader_.LoadImageAsync(
+ extension_, extension_->GetResource(path), gfx::Size(size, size),
+ base::Bind(&TestImageLoader::OnImageLoaded,
+ base::Unretained(this)));
// If |image_| still hasn't been loaded (i.e. it is being loaded
// asynchronously), wait for it.
@@ -113,7 +108,7 @@ class TestImageLoader : public ImageLoadingTracker::Observer {
bool waiting_;
bool image_loaded_;
gfx::Image image_;
- ImageLoadingTracker tracker_;
+ extensions::ImageLoader image_loader_;
DISALLOW_COPY_AND_ASSIGN(TestImageLoader);
};
@@ -192,10 +187,9 @@ class ExtensionIconImageTest : public testing::Test,
// The image will be loaded from the relative path |path|.
SkBitmap GetTestBitmap(const Extension* extension,
const std::string& path,
- int size,
- ImageLoadingTracker::CacheParam cache_param) {
+ int size) {
TestImageLoader image_loader(extension);
- return image_loader.LoadBitmap(path, size, cache_param);
+ return image_loader.LoadBitmap(path, size);
}
private:
@@ -221,13 +215,13 @@ TEST_F(ExtensionIconImageTest, Basic) {
// Load images we expect to find as representations in icon_image, so we
// can later use them to validate icon_image.
SkBitmap bitmap_16 =
- GetTestBitmap(extension, "16.png", 16, ImageLoadingTracker::DONT_CACHE);
+ GetTestBitmap(extension, "16.png", 16);
ASSERT_FALSE(bitmap_16.empty());
// There is no image of size 32 defined in the extension manifest, so we
// should expect manifest image of size 48 resized to size 32.
SkBitmap bitmap_48_resized_to_32 =
- GetTestBitmap(extension, "48.png", 32, ImageLoadingTracker::DONT_CACHE);
+ GetTestBitmap(extension, "48.png", 32);
ASSERT_FALSE(bitmap_48_resized_to_32.empty());
IconImage image(extension, extension->icons(), 16, default_icon, this);
@@ -287,7 +281,7 @@ TEST_F(ExtensionIconImageTest, FallbackToSmallerWhenNoBigger) {
// Load images we expect to find as representations in icon_image, so we
// can later use them to validate icon_image.
SkBitmap bitmap_48 =
- GetTestBitmap(extension, "48.png", 48, ImageLoadingTracker::DONT_CACHE);
+ GetTestBitmap(extension, "48.png", 48);
ASSERT_FALSE(bitmap_48.empty());
IconImage image(extension, extension->icons(), 32, default_icon, this);
@@ -322,7 +316,7 @@ TEST_F(ExtensionIconImageTest, FallbackToSmaller) {
// Load images we expect to find as representations in icon_image, so we
// can later use them to validate icon_image.
SkBitmap bitmap_16 =
- GetTestBitmap(extension, "16.png", 16, ImageLoadingTracker::DONT_CACHE);
+ GetTestBitmap(extension, "16.png", 16);
ASSERT_FALSE(bitmap_16.empty());
IconImage image(extension, extension->icons(), 17, default_icon, this);
@@ -474,10 +468,12 @@ TEST_F(ExtensionIconImageTest, LoadPrecachedImage) {
gfx::ImageSkia default_icon = GetDefaultIcon();
- // Note the cache parameter.
+ // Store the image in the cache.
SkBitmap bitmap_16 =
- GetTestBitmap(extension, "16.png", 16, ImageLoadingTracker::CACHE);
+ GetTestBitmap(extension, "16.png", 16);
ASSERT_FALSE(bitmap_16.empty());
+ extension->SetCachedImage(extension->GetResource("16.png"), bitmap_16,
+ gfx::Size(16, 16));
IconImage image(extension, extension->icons(), 16, default_icon, this);
@@ -510,7 +506,7 @@ TEST_F(ExtensionIconImageTest, IconImageDestruction) {
// Load images we expect to find as representations in icon_image, so we
// can later use them to validate icon_image.
SkBitmap bitmap_16 =
- GetTestBitmap(extension, "16.png", 16, ImageLoadingTracker::DONT_CACHE);
+ GetTestBitmap(extension, "16.png", 16);
ASSERT_FALSE(bitmap_16.empty());
scoped_ptr<IconImage> image(
diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc
index dff6daa..f38287f 100644
--- a/chrome/browser/extensions/extension_install_prompt.cc
+++ b/chrome/browser/extensions/extension_install_prompt.cc
@@ -15,6 +15,7 @@
#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/bundle_installer.h"
#include "chrome/browser/extensions/extension_install_ui.h"
+#include "chrome/browser/extensions/image_loader.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/token_service.h"
@@ -376,9 +377,9 @@ ExtensionInstallPrompt::ExtensionInstallPrompt(
extension_(NULL),
install_ui_(ExtensionInstallUI::Create(ProfileForWebContents(contents))),
delegate_(NULL),
- prompt_(ProfileForWebContents(contents), UNSET_PROMPT_TYPE),
- prompt_type_(UNSET_PROMPT_TYPE),
- ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) {
+ profile_(ProfileForWebContents(contents)),
+ prompt_(profile_, UNSET_PROMPT_TYPE),
+ prompt_type_(UNSET_PROMPT_TYPE) {
}
ExtensionInstallPrompt::~ExtensionInstallPrompt() {
@@ -529,16 +530,15 @@ void ExtensionInstallPrompt::SetIcon(const SkBitmap* image) {
}
}
-void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image& image,
- const std::string& extension_id,
- int index) {
+void ExtensionInstallPrompt::OnImageLoaded(const gfx::Image& image) {
SetIcon(image.IsEmpty() ? NULL : image.ToSkBitmap());
FetchOAuthIssueAdviceIfNeeded();
}
void ExtensionInstallPrompt::LoadImageIfNeeded() {
// Bundle install prompts do not have an icon.
- if (!icon_.empty()) {
+ // Also |profile_| can be NULL in unit tests.
+ if (!icon_.empty() || !profile_) {
FetchOAuthIssueAdviceIfNeeded();
return;
}
@@ -552,9 +552,9 @@ void ExtensionInstallPrompt::LoadImageIfNeeded() {
// TODO(tbarzic): We should use IconImage here and load the required bitmap
// lazily.
int pixel_size = GetSizeForMaxScaleFactor(kIconSize);
- tracker_.LoadImage(extension_, image,
- gfx::Size(pixel_size, pixel_size),
- ImageLoadingTracker::DONT_CACHE);
+ extensions::ImageLoader::Get(profile_)->LoadImageAsync(
+ extension_, image, gfx::Size(pixel_size, pixel_size),
+ base::Bind(&ExtensionInstallPrompt::OnImageLoaded, AsWeakPtr()));
}
void ExtensionInstallPrompt::FetchOAuthIssueAdviceIfNeeded() {
diff --git a/chrome/browser/extensions/extension_install_prompt.h b/chrome/browser/extensions/extension_install_prompt.h
index 2d3914a..ad89799 100644
--- a/chrome/browser/extensions/extension_install_prompt.h
+++ b/chrome/browser/extensions/extension_install_prompt.h
@@ -13,7 +13,6 @@
#include "base/memory/scoped_ptr.h"
#include "base/string16.h"
#include "chrome/browser/extensions/crx_installer_error.h"
-#include "chrome/browser/extensions/image_loading_tracker.h"
#include "extensions/common/url_pattern.h"
#include "google_apis/gaia/oauth2_mint_token_flow.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -43,8 +42,9 @@ class PermissionSet;
} // namespace extensions
// Displays all the UI around extension installation.
-class ExtensionInstallPrompt : public ImageLoadingTracker::Observer,
- public OAuth2MintTokenFlow::Delegate {
+class ExtensionInstallPrompt
+ : public OAuth2MintTokenFlow::Delegate,
+ public base::SupportsWeakPtr<ExtensionInstallPrompt> {
public:
enum PromptType {
UNSET_PROMPT_TYPE = -1,
@@ -260,11 +260,6 @@ class ExtensionInstallPrompt : public ImageLoadingTracker::Observer,
// Installation failed. This is declared virtual for testing.
virtual void OnInstallFailure(const extensions::CrxInstallerError& error);
- // ImageLoadingTracker::Observer:
- virtual void OnImageLoaded(const gfx::Image& image,
- const std::string& extension_id,
- int index) OVERRIDE;
-
protected:
friend class extensions::ExtensionWebstorePrivateApiTest;
friend class WebstoreStandaloneInstallUnpackFailureTest;
@@ -280,6 +275,9 @@ class ExtensionInstallPrompt : public ImageLoadingTracker::Observer,
// an empty bitmap, then a default icon will be used instead.
void SetIcon(const SkBitmap* icon);
+ // ImageLoader callback.
+ void OnImageLoaded(const gfx::Image& image);
+
// Starts the process of showing a confirmation UI, which is split into two.
// 1) Set off a 'load icon' task.
// 2) Handle the load icon response and show the UI (OnImageLoaded).
@@ -319,6 +317,8 @@ class ExtensionInstallPrompt : public ImageLoadingTracker::Observer,
// The delegate we will call Proceed/Abort on after confirmation UI.
Delegate* delegate_;
+ Profile* profile_;
+
// A pre-filled prompt.
Prompt prompt_;
@@ -327,10 +327,6 @@ class ExtensionInstallPrompt : public ImageLoadingTracker::Observer,
scoped_ptr<OAuth2MintTokenFlow> token_flow_;
- // Keeps track of extension images being loaded on the File thread for the
- // purpose of showing the install UI.
- ImageLoadingTracker tracker_;
-
// Used to show the confirm dialog.
ShowDialogCallback show_dialog_callback_;
};
diff --git a/chrome/browser/extensions/extension_protocols.cc b/chrome/browser/extensions/extension_protocols.cc
index f33300d..a9edd50 100644
--- a/chrome/browser/extensions/extension_protocols.cc
+++ b/chrome/browser/extensions/extension_protocols.cc
@@ -18,7 +18,7 @@
#include "base/threading/worker_pool.h"
#include "build/build_config.h"
#include "chrome/browser/extensions/extension_info_map.h"
-#include "chrome/browser/extensions/image_loading_tracker.h"
+#include "chrome/browser/extensions/image_loader.h"
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension.h"
@@ -378,7 +378,7 @@ ExtensionProtocolHandler::MaybeCreateJob(
FilePath request_path =
extension_file_util::ExtensionURLToRelativeFilePath(request->url());
int resource_id;
- if (ImageLoadingTracker::IsComponentExtensionResource(extension,
+ if (extensions::ImageLoader::IsComponentExtensionResource(extension,
request_path, &resource_id)) {
relative_path = relative_path.Append(request_path);
relative_path = relative_path.NormalizePathSeparators();
diff --git a/chrome/browser/extensions/extension_system.h b/chrome/browser/extensions/extension_system.h
index ca3ac3e..cbab7f8 100644
--- a/chrome/browser/extensions/extension_system.h
+++ b/chrome/browser/extensions/extension_system.h
@@ -164,8 +164,9 @@ class ExtensionSystemImpl : public ExtensionSystem {
virtual ExtensionDevToolsManager* devtools_manager() OVERRIDE;
virtual ExtensionProcessManager* process_manager() OVERRIDE;
virtual AlarmManager* alarm_manager() OVERRIDE;
- virtual StateStore* state_store() OVERRIDE;
- virtual ShellWindowGeometryCache* shell_window_geometry_cache() OVERRIDE;
+ virtual StateStore* state_store() OVERRIDE; // shared
+ virtual ShellWindowGeometryCache* shell_window_geometry_cache()
+ OVERRIDE; // shared
virtual LazyBackgroundTaskQueue* lazy_background_task_queue()
OVERRIDE; // shared
virtual ExtensionInfoMap* info_map() OVERRIDE; // shared
diff --git a/chrome/browser/extensions/extension_web_ui.cc b/chrome/browser/extensions/extension_web_ui.cc
index b98641a..08f05d3 100644
--- a/chrome/browser/extensions/extension_web_ui.cc
+++ b/chrome/browser/extensions/extension_web_ui.cc
@@ -13,7 +13,7 @@
#include "chrome/browser/bookmarks/bookmark_manager_extension_api.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tab_util.h"
-#include "chrome/browser/extensions/image_loading_tracker.h"
+#include "chrome/browser/extensions/image_loader.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/profiles/profile.h"
@@ -78,113 +78,49 @@ void UnregisterAndReplaceOverrideForWebContents(
content::PAGE_TRANSITION_RELOAD, std::string());
}
-// Helper class that is used to track the loading of the favicon of an
-// extension.
-class ExtensionWebUIImageLoadingTracker : public ImageLoadingTracker::Observer {
- public:
- ExtensionWebUIImageLoadingTracker(Profile* profile,
- FaviconService::GetFaviconRequest* request,
- const GURL& page_url)
- : ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)),
- request_(request),
- extension_(NULL) {
- // Even when the extensions service is enabled by default, it's still
- // disabled in incognito mode.
- ExtensionService* service = profile->GetExtensionService();
- if (service)
- extension_ = service->extensions()->GetByID(page_url.host());
- }
-
- void Init() {
- if (extension_) {
- // Fetch resources for all supported scale factors for which there are
- // resources. Load image reps for all supported scale factors immediately
- // instead of in an as needed fashion to be consistent with how favicons
- // are requested for chrome:// and page URLs.
- const std::vector<ui::ScaleFactor>& scale_factors =
- ui::GetSupportedScaleFactors();
- std::vector<ImageLoadingTracker::ImageRepresentation> info_list;
- for (size_t i = 0; i < scale_factors.size(); ++i) {
- float scale = ui::GetScaleFactorScale(scale_factors[i]);
- int pixel_size = static_cast<int>(gfx::kFaviconSize * scale);
- ExtensionResource icon_resource =
- extension_->GetIconResource(pixel_size,
- ExtensionIconSet::MATCH_BIGGER);
-
- info_list.push_back(
- ImageLoadingTracker::ImageRepresentation(
- icon_resource,
- ImageLoadingTracker::ImageRepresentation::ALWAYS_RESIZE,
- gfx::Size(pixel_size, pixel_size),
- scale_factors[i]));
- }
-
- tracker_.LoadImages(extension_, info_list,
- ImageLoadingTracker::DONT_CACHE);
+// Forwards the result of the request. If no favicon was available then
+// |image| will be empty. Once the result has been forwarded the instance is
+// deleted.
+void ForwardFaviconResult(FaviconService::GetFaviconRequest* request,
+ const gfx::Image& image) {
+ std::vector<history::FaviconBitmapResult> favicon_bitmap_results;
+ const std::vector<gfx::ImageSkiaRep>& image_reps =
+ image.AsImageSkia().image_reps();
+ for (size_t i = 0; i < image_reps.size(); ++i) {
+ const gfx::ImageSkiaRep& image_rep = image_reps[i];
+ scoped_refptr<base::RefCountedBytes> bitmap_data(
+ new base::RefCountedBytes());
+ if (gfx::PNGCodec::EncodeBGRASkBitmap(image_rep.sk_bitmap(),
+ false,
+ &bitmap_data->data())) {
+ history::FaviconBitmapResult bitmap_result;
+ bitmap_result.bitmap_data = bitmap_data;
+ bitmap_result.pixel_size = gfx::Size(image_rep.pixel_width(),
+ image_rep.pixel_height());
+ // Leave |bitmap_result|'s icon URL as the default of GURL().
+ bitmap_result.icon_type = history::FAVICON;
+
+ favicon_bitmap_results.push_back(bitmap_result);
} else {
- ForwardResult(gfx::Image());
+ NOTREACHED() << "Could not encode extension favicon";
}
}
- virtual void OnImageLoaded(const gfx::Image& image,
- const std::string& extension_id,
- int index) OVERRIDE {
- ForwardResult(image);
- }
-
- private:
- ~ExtensionWebUIImageLoadingTracker() {}
-
- // Forwards the result of the request. If no favicon was available then
- // |image| will be empty. Once the result has been forwarded the instance is
- // deleted.
- void ForwardResult(const gfx::Image& image) {
- std::vector<history::FaviconBitmapResult> favicon_bitmap_results;
- const std::vector<gfx::ImageSkiaRep>& image_reps =
- image.AsImageSkia().image_reps();
- for (size_t i = 0; i < image_reps.size(); ++i) {
- const gfx::ImageSkiaRep& image_rep = image_reps[i];
- scoped_refptr<base::RefCountedBytes> bitmap_data(
- new base::RefCountedBytes());
- if (gfx::PNGCodec::EncodeBGRASkBitmap(image_rep.sk_bitmap(),
- false,
- &bitmap_data->data())) {
- history::FaviconBitmapResult bitmap_result;
- bitmap_result.bitmap_data = bitmap_data;
- bitmap_result.pixel_size = gfx::Size(image_rep.pixel_width(),
- image_rep.pixel_height());
- // Leave |bitmap_result|'s icon URL as the default of GURL().
- bitmap_result.icon_type = history::FAVICON;
-
- favicon_bitmap_results.push_back(bitmap_result);
- } else {
- NOTREACHED() << "Could not encode extension favicon";
- }
- }
-
- // Populate IconURLSizesMap such that all the icon URLs in
- // |favicon_bitmap_results| are present in |icon_url_sizes|.
- // Populate the favicon sizes with the relevant pixel sizes in the
- // extension's icon set.
- history::IconURLSizesMap icon_url_sizes;
- for (size_t i = 0; i < favicon_bitmap_results.size(); ++i) {
- const history::FaviconBitmapResult& bitmap_result =
- favicon_bitmap_results[i];
- const GURL& icon_url = bitmap_result.icon_url;
- icon_url_sizes[icon_url].push_back(bitmap_result.pixel_size);
- }
-
- request_->ForwardResultAsync(request_->handle(), favicon_bitmap_results,
- icon_url_sizes);
- delete this;
+ // Populate IconURLSizesMap such that all the icon URLs in
+ // |favicon_bitmap_results| are present in |icon_url_sizes|.
+ // Populate the favicon sizes with the relevant pixel sizes in the
+ // extension's icon set.
+ history::IconURLSizesMap icon_url_sizes;
+ for (size_t i = 0; i < favicon_bitmap_results.size(); ++i) {
+ const history::FaviconBitmapResult& bitmap_result =
+ favicon_bitmap_results[i];
+ const GURL& icon_url = bitmap_result.icon_url;
+ icon_url_sizes[icon_url].push_back(bitmap_result.pixel_size);
}
- ImageLoadingTracker tracker_;
- scoped_refptr<FaviconService::GetFaviconRequest> request_;
- const Extension* extension_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionWebUIImageLoadingTracker);
-};
+ request->ForwardResultAsync(request->handle(), favicon_bitmap_results,
+ icon_url_sizes);
+}
} // namespace
@@ -464,8 +400,43 @@ void ExtensionWebUI::UnregisterChromeURLOverrides(
// static
void ExtensionWebUI::GetFaviconForURL(Profile* profile,
FaviconService::GetFaviconRequest* request, const GURL& page_url) {
- // tracker deletes itself when done.
- ExtensionWebUIImageLoadingTracker* tracker =
- new ExtensionWebUIImageLoadingTracker(profile, request, page_url);
- tracker->Init();
+ // Even when the extensions service is enabled by default, it's still
+ // disabled in incognito mode.
+ ExtensionService* service = profile->GetExtensionService();
+ if (!service) {
+ ForwardFaviconResult(request, gfx::Image());
+ return;
+ }
+ const Extension* extension = service->extensions()->GetByID(page_url.host());
+ if (!extension) {
+ ForwardFaviconResult(request, gfx::Image());
+ return;
+ }
+
+ // Fetch resources for all supported scale factors for which there are
+ // resources. Load image reps for all supported scale factors immediately
+ // instead of in an as needed fashion to be consistent with how favicons
+ // are requested for chrome:// and page URLs.
+ const std::vector<ui::ScaleFactor>& scale_factors =
+ ui::GetSupportedScaleFactors();
+ std::vector<extensions::ImageLoader::ImageRepresentation> info_list;
+ for (size_t i = 0; i < scale_factors.size(); ++i) {
+ float scale = ui::GetScaleFactorScale(scale_factors[i]);
+ int pixel_size = static_cast<int>(gfx::kFaviconSize * scale);
+ ExtensionResource icon_resource =
+ extension->GetIconResource(pixel_size,
+ ExtensionIconSet::MATCH_BIGGER);
+
+ info_list.push_back(
+ extensions::ImageLoader::ImageRepresentation(
+ icon_resource,
+ extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
+ gfx::Size(pixel_size, pixel_size),
+ scale_factors[i]));
+ }
+
+ extensions::ImageLoader::Get(profile)->LoadImagesAsync(
+ extension, info_list,
+ base::Bind(&ForwardFaviconResult,
+ scoped_refptr<FaviconService::GetFaviconRequest>(request)));
}
diff --git a/chrome/browser/extensions/image_loader.cc b/chrome/browser/extensions/image_loader.cc
new file mode 100644
index 0000000..8060410
--- /dev/null
+++ b/chrome/browser/extensions/image_loader.cc
@@ -0,0 +1,327 @@
+// 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/image_loader.h"
+
+#include "base/callback.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/string_number_conversions.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/extensions/image_loader_factory.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/extension.h"
+#include "content/public/browser/browser_thread.h"
+#include "grit/chrome_unscaled_resources.h"
+#include "grit/component_extension_resources_map.h"
+#include "grit/theme_resources.h"
+#include "skia/ext/image_operations.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/image/image_skia.h"
+#include "webkit/glue/image_decoder.h"
+
+using content::BrowserThread;
+using extensions::Extension;
+using extensions::ImageLoader;
+
+namespace {
+
+bool ShouldResizeImageRepresentation(
+ ImageLoader::ImageRepresentation::ResizeCondition resize_method,
+ const gfx::Size& decoded_size,
+ const gfx::Size& desired_size) {
+ switch (resize_method) {
+ case ImageLoader::ImageRepresentation::ALWAYS_RESIZE:
+ return decoded_size != desired_size;
+ case ImageLoader::ImageRepresentation::RESIZE_WHEN_LARGER:
+ return decoded_size.width() > desired_size.width() ||
+ decoded_size.height() > desired_size.height();
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
+SkBitmap ResizeIfNeeded(const SkBitmap& bitmap,
+ const ImageLoader::ImageRepresentation& image_info) {
+ gfx::Size original_size(bitmap.width(), bitmap.height());
+ if (ShouldResizeImageRepresentation(image_info.resize_condition,
+ original_size,
+ image_info.desired_size)) {
+ return skia::ImageOperations::Resize(
+ bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
+ image_info.desired_size.width(), image_info.desired_size.height());
+ }
+
+ return bitmap;
+}
+
+void LoadResourceOnUIThread(int resource_id, SkBitmap* bitmap) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ gfx::ImageSkia image(
+ *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id));
+ image.MakeThreadSafe();
+ *bitmap = *image.bitmap();
+}
+
+void LoadImageOnBlockingPool(const ImageLoader::ImageRepresentation& image_info,
+ SkBitmap* bitmap) {
+ DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
+
+ // Read the file from disk.
+ std::string file_contents;
+ FilePath path = image_info.resource.GetFilePath();
+ if (path.empty() || !file_util::ReadFileToString(path, &file_contents)) {
+ return;
+ }
+
+ // Decode the bitmap using WebKit's image decoder.
+ const unsigned char* data =
+ reinterpret_cast<const unsigned char*>(file_contents.data());
+ webkit_glue::ImageDecoder decoder;
+ // Note: This class only decodes bitmaps from extension resources. Chrome
+ // doesn't (for security reasons) directly load extension resources provided
+ // by the extension author, but instead decodes them in a separate
+ // locked-down utility process. Only if the decoding succeeds is the image
+ // saved from memory to disk and subsequently used in the Chrome UI.
+ // Chrome is therefore decoding bitmaps here that were generated by Chrome.
+ *bitmap = decoder.Decode(data, file_contents.length());
+}
+
+} // namespace
+
+namespace extensions {
+
+////////////////////////////////////////////////////////////////////////////////
+// ImageLoader::ImageRepresentation
+
+ImageLoader::ImageRepresentation::ImageRepresentation(
+ const ExtensionResource& resource,
+ ResizeCondition resize_condition,
+ const gfx::Size& desired_size,
+ ui::ScaleFactor scale_factor)
+ : resource(resource),
+ resize_condition(resize_condition),
+ desired_size(desired_size),
+ scale_factor(scale_factor) {
+}
+
+ImageLoader::ImageRepresentation::~ImageRepresentation() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ImageLoader::LoadResult
+
+struct ImageLoader::LoadResult {
+ LoadResult(const SkBitmap& bitmap,
+ const gfx::Size& original_size,
+ const ImageRepresentation& image_representation);
+ ~LoadResult();
+
+ SkBitmap bitmap;
+ gfx::Size original_size;
+ ImageRepresentation image_representation;
+};
+
+ImageLoader::LoadResult::LoadResult(
+ const SkBitmap& bitmap,
+ const gfx::Size& original_size,
+ const ImageLoader::ImageRepresentation& image_representation)
+ : bitmap(bitmap),
+ original_size(original_size),
+ image_representation(image_representation) {
+}
+
+ImageLoader::LoadResult::~LoadResult() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ImageLoader
+
+ImageLoader::ImageLoader() {
+}
+
+ImageLoader::~ImageLoader() {
+}
+
+// static
+ImageLoader* ImageLoader::Get(Profile* profile) {
+ return ImageLoaderFactory::GetForProfile(profile);
+}
+
+// static
+bool ImageLoader::IsComponentExtensionResource(const Extension* extension,
+ const FilePath& resource_path,
+ int* resource_id) {
+ static const GritResourceMap kExtraComponentExtensionResources[] = {
+ {"web_store/webstore_icon_128.png", IDR_WEBSTORE_ICON},
+ {"web_store/webstore_icon_16.png", IDR_WEBSTORE_ICON_16},
+ {"chrome_app/product_logo_128.png", IDR_PRODUCT_LOGO_128},
+ {"chrome_app/product_logo_16.png", IDR_PRODUCT_LOGO_16},
+ {"settings_app/settings_app_icon_128.png", IDR_SETTINGS_APP_ICON_128},
+ {"settings_app/settings_app_icon_16.png", IDR_SETTINGS_APP_ICON_16},
+ };
+ static const size_t kExtraComponentExtensionResourcesSize =
+ arraysize(kExtraComponentExtensionResources);
+
+ if (extension->location() != Extension::COMPONENT)
+ return false;
+
+ FilePath directory_path = extension->path();
+ FilePath resources_dir;
+ FilePath relative_path;
+ if (!PathService::Get(chrome::DIR_RESOURCES, &resources_dir) ||
+ !resources_dir.AppendRelativePath(directory_path, &relative_path)) {
+ return false;
+ }
+ relative_path = relative_path.Append(resource_path);
+ relative_path = relative_path.NormalizePathSeparators();
+
+ // TODO(tc): Make a map of FilePath -> resource ids so we don't have to
+ // covert to FilePaths all the time. This will be more useful as we add
+ // more resources.
+ for (size_t i = 0; i < kComponentExtensionResourcesSize; ++i) {
+ FilePath resource_path =
+ FilePath().AppendASCII(kComponentExtensionResources[i].name);
+ resource_path = resource_path.NormalizePathSeparators();
+
+ if (relative_path == resource_path) {
+ *resource_id = kComponentExtensionResources[i].value;
+ return true;
+ }
+ }
+ for (size_t i = 0; i < kExtraComponentExtensionResourcesSize; ++i) {
+ FilePath resource_path =
+ FilePath().AppendASCII(kExtraComponentExtensionResources[i].name);
+ resource_path = resource_path.NormalizePathSeparators();
+
+ if (relative_path == resource_path) {
+ *resource_id = kExtraComponentExtensionResources[i].value;
+ return true;
+ }
+ }
+ return false;
+}
+
+void ImageLoader::LoadImageAsync(
+ const Extension* extension,
+ const ExtensionResource& resource,
+ const gfx::Size& max_size,
+ const base::Callback<void(const gfx::Image&)>& callback) {
+ std::vector<ImageRepresentation> info_list;
+ info_list.push_back(ImageRepresentation(
+ resource,
+ ImageRepresentation::RESIZE_WHEN_LARGER,
+ max_size,
+ ui::SCALE_FACTOR_100P));
+ LoadImagesAsync(extension, info_list, callback);
+}
+
+void ImageLoader::LoadImagesAsync(
+ const Extension* extension,
+ const std::vector<ImageRepresentation>& info_list,
+ const base::Callback<void(const gfx::Image&)>& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // Loading an image from the cache and loading resources have to happen
+ // on the UI thread. So do those two things first, and pass the rest of the
+ // work of as a blocking pool task.
+
+ std::vector<SkBitmap> bitmaps;
+ bitmaps.resize(info_list.size());
+
+ int i = 0;
+ for (std::vector<ImageRepresentation>::const_iterator it = info_list.begin();
+ it != info_list.end(); ++it, ++i) {
+ DCHECK(it->resource.relative_path().empty() ||
+ extension->path() == it->resource.extension_root());
+
+ int resource_id;
+ if (IsComponentExtensionResource(extension, it->resource.relative_path(),
+ &resource_id)) {
+ LoadResourceOnUIThread(resource_id, &bitmaps[i]);
+ }
+ }
+
+ DCHECK(!BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
+ BrowserThread::PostBlockingPoolTask(
+ FROM_HERE,
+ base::Bind(&ImageLoader::LoadImagesOnBlockingPool, base::Unretained(this),
+ info_list, bitmaps, callback));
+}
+
+void ImageLoader::LoadImagesOnBlockingPool(
+ const std::vector<ImageRepresentation>& info_list,
+ const std::vector<SkBitmap>& bitmaps,
+ const base::Callback<void(const gfx::Image&)>& callback) {
+ DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
+
+ gfx::ImageSkia image_skia;
+
+ std::vector<LoadResult> load_result;
+
+ int i = 0;
+ for (std::vector<ImageRepresentation>::const_iterator it = info_list.begin();
+ it != info_list.end(); ++it, ++i) {
+ // If we don't have a path there isn't anything we can do, just skip it.
+ if (it->resource.relative_path().empty())
+ continue;
+
+ SkBitmap bitmap;
+ if (!bitmaps[i].isNull()) {
+ bitmap = bitmaps[i];
+ } else {
+ LoadImageOnBlockingPool(*it, &bitmap);
+ }
+
+ // If the image failed to load, skip it.
+ if (bitmap.isNull() || bitmap.empty())
+ continue;
+
+ gfx::Size original_size(bitmap.width(), bitmap.height());
+ bitmap = ResizeIfNeeded(bitmap, *it);
+
+ load_result.push_back(LoadResult(bitmap, original_size, *it));
+ }
+
+ gfx::Image image;
+
+ if (!image_skia.isNull()) {
+ image_skia.MakeThreadSafe();
+ image = gfx::Image(image_skia);
+ }
+
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(&ImageLoader::ReplyBack,
+ base::Unretained(this), load_result,
+ callback));
+}
+
+void ImageLoader::ReplyBack(
+ const std::vector<LoadResult>& load_result,
+ const base::Callback<void(const gfx::Image&)>& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ gfx::ImageSkia image_skia;
+
+ for (std::vector<LoadResult>::const_iterator it = load_result.begin();
+ it != load_result.end(); ++it) {
+ const SkBitmap& bitmap = it->bitmap;
+ const ImageRepresentation& image_rep = it->image_representation;
+
+ image_skia.AddRepresentation(gfx::ImageSkiaRep(
+ bitmap, image_rep.scale_factor));
+ }
+
+ gfx::Image image;
+ if (!image_skia.isNull()) {
+ image_skia.MakeThreadSafe();
+ image = gfx::Image(image_skia);
+ }
+
+ callback.Run(image);
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/image_loader.h b/chrome/browser/extensions/image_loader.h
new file mode 100644
index 0000000..44af106
--- /dev/null
+++ b/chrome/browser/extensions/image_loader.h
@@ -0,0 +1,113 @@
+// 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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_IMAGE_LOADER_H_
+#define CHROME_BROWSER_EXTENSIONS_IMAGE_LOADER_H_
+
+#include <map>
+#include <set>
+
+#include "base/callback_forward.h"
+#include "base/gtest_prod_util.h"
+#include "chrome/browser/profiles/profile_keyed_service.h"
+#include "chrome/common/extensions/extension_resource.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/layout.h"
+#include "ui/gfx/size.h"
+
+class Profile;
+
+namespace gfx {
+class Image;
+}
+
+namespace extensions {
+
+class Extension;
+
+// This class is responsible for asynchronously loading extension images and
+// calling a callback when an image is loaded.
+// The views need to load their icons asynchronously might be deleted before
+// the images have loaded. If you pass your callback using a weak_ptr, this
+// will make sure the callback won't be called after the view is deleted.
+class ImageLoader : public ProfileKeyedService {
+ public:
+ // Information about a singe image representation to load from an extension
+ // resource.
+ struct ImageRepresentation {
+ // Enum values to indicate whether to resize loaded bitmap when it is larger
+ // than |desired_size| or always resize it.
+ enum ResizeCondition {
+ RESIZE_WHEN_LARGER,
+ ALWAYS_RESIZE,
+ };
+
+ ImageRepresentation(const ExtensionResource& resource,
+ ResizeCondition resize_condition,
+ const gfx::Size& desired_size,
+ ui::ScaleFactor scale_factor);
+ ~ImageRepresentation();
+
+ // Extension resource to load.
+ ExtensionResource resource;
+
+ ResizeCondition resize_condition;
+
+ // When |resize_method| is ALWAYS_RESIZE or when the loaded image is larger
+ // than |desired_size| it will be resized to these dimensions.
+ gfx::Size desired_size;
+
+ // |scale_factor| is used to construct the loaded gfx::ImageSkia.
+ ui::ScaleFactor scale_factor;
+ };
+
+ // Returns the instance for the given profile, or NULL if none. This is
+ // a convenience wrapper around ImageLoaderFactory::GetForProfile.
+ static ImageLoader* Get(Profile* profile);
+
+ ImageLoader();
+ virtual ~ImageLoader();
+
+ // Checks whether image is a component extension resource. Returns false
+ // if a given |resource| does not have a corresponding image in bundled
+ // resources. Otherwise fills |resource_id|.
+ static bool IsComponentExtensionResource(
+ const extensions::Extension* extension,
+ const FilePath& resource_path,
+ int* resource_id);
+
+ // Specify image resource to load. If the loaded image is larger than
+ // |max_size| it will be resized to those dimensions. IMPORTANT NOTE: this
+ // function may call back your callback synchronously (ie before it returns)
+ // if the image was found in the cache.
+ // Note this method loads a raw bitmap from the resource. All sizes given are
+ // assumed to be in pixels.
+ void LoadImageAsync(const extensions::Extension* extension,
+ const ExtensionResource& resource,
+ const gfx::Size& max_size,
+ const base::Callback<void(const gfx::Image&)>& callback);
+
+ // Same as LoadImage() above except it loads multiple images from the same
+ // extension. This is used to load multiple resolutions of the same image
+ // type.
+ void LoadImagesAsync(const extensions::Extension* extension,
+ const std::vector<ImageRepresentation>& info_list,
+ const base::Callback<void(const gfx::Image&)>& callback);
+
+ private:
+ struct LoadResult;
+
+ void LoadImagesOnBlockingPool(
+ const std::vector<ImageRepresentation>& info_list,
+ const std::vector<SkBitmap>& bitmaps,
+ const base::Callback<void(const gfx::Image&)>& callback);
+
+ void ReplyBack(
+ const std::vector<LoadResult>& load_result,
+ const base::Callback<void(const gfx::Image&)>& callback);
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_IMAGE_LOADER_H_
diff --git a/chrome/browser/extensions/image_loader_factory.cc b/chrome/browser/extensions/image_loader_factory.cc
new file mode 100644
index 0000000..21ad9ad
--- /dev/null
+++ b/chrome/browser/extensions/image_loader_factory.cc
@@ -0,0 +1,50 @@
+// 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/image_loader_factory.h"
+
+#include "chrome/browser/extensions/image_loader.h"
+#include "chrome/browser/profiles/profile_dependency_manager.h"
+
+namespace extensions {
+
+// static
+ImageLoader* ImageLoaderFactory::GetForProfile(Profile* profile) {
+ return static_cast<ImageLoader*>(
+ GetInstance()->GetServiceForProfile(profile, true));
+}
+
+// static
+void ImageLoaderFactory::ResetForProfile(Profile* profile) {
+ ImageLoaderFactory* factory = GetInstance();
+ factory->ProfileShutdown(profile);
+ factory->ProfileDestroyed(profile);
+}
+
+ImageLoaderFactory* ImageLoaderFactory::GetInstance() {
+ return Singleton<ImageLoaderFactory>::get();
+}
+
+ImageLoaderFactory::ImageLoaderFactory()
+ : ProfileKeyedServiceFactory("ImageLoader",
+ ProfileDependencyManager::GetInstance()) {
+}
+
+ImageLoaderFactory::~ImageLoaderFactory() {
+}
+
+ProfileKeyedService* ImageLoaderFactory::BuildServiceInstanceFor(
+ Profile* profile) const {
+ return new ImageLoader;
+}
+
+bool ImageLoaderFactory::ServiceIsCreatedWithProfile() const {
+ return false;
+}
+
+bool ImageLoaderFactory::ServiceRedirectedInIncognito() const {
+ return true;
+}
+
+} // namespace extensions
diff --git a/chrome/browser/extensions/image_loader_factory.h b/chrome/browser/extensions/image_loader_factory.h
new file mode 100644
index 0000000..767316b
--- /dev/null
+++ b/chrome/browser/extensions/image_loader_factory.h
@@ -0,0 +1,43 @@
+// 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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_IMAGE_LOADER_FACTORY_H_
+#define CHROME_BROWSER_EXTENSIONS_IMAGE_LOADER_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/profiles/profile_keyed_service_factory.h"
+
+class Profile;
+
+namespace extensions {
+
+class ImageLoader;
+
+// Singleton that owns all ImageLoaders and associates them with
+// Profiles. Listens for the Profile's destruction notification and cleans up
+// the associated ImageLoader.
+class ImageLoaderFactory : public ProfileKeyedServiceFactory {
+ public:
+ static ImageLoader* GetForProfile(Profile* profile);
+
+ static void ResetForProfile(Profile* profile);
+
+ static ImageLoaderFactory* GetInstance();
+
+ private:
+ friend struct DefaultSingletonTraits<ImageLoaderFactory>;
+
+ ImageLoaderFactory();
+ virtual ~ImageLoaderFactory();
+
+ // ProfileKeyedServiceFactory:
+ virtual ProfileKeyedService* BuildServiceInstanceFor(
+ Profile* profile) const OVERRIDE;
+ virtual bool ServiceIsCreatedWithProfile() const OVERRIDE;
+ virtual bool ServiceRedirectedInIncognito() const OVERRIDE;
+};
+
+} // namespace extensions
+
+#endif // CHROME_BROWSER_EXTENSIONS_IMAGE_LOADER_FACTORY_H_
diff --git a/chrome/browser/extensions/image_loader_unittest.cc b/chrome/browser/extensions/image_loader_unittest.cc
new file mode 100644
index 0000000..8b0b483
--- /dev/null
+++ b/chrome/browser/extensions/image_loader_unittest.cc
@@ -0,0 +1,252 @@
+// 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/image_loader.h"
+
+#include "base/json/json_file_value_serializer.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension_icon_set.h"
+#include "chrome/common/extensions/extension_resource.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/test/test_browser_thread.h"
+#include "grit/component_extension_resources.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/size.h"
+
+using content::BrowserThread;
+using extensions::Extension;
+using extensions::ImageLoader;
+
+class ImageLoaderTest : public testing::Test {
+ public:
+ ImageLoaderTest()
+ : image_loaded_count_(0),
+ quit_in_image_loaded_(false),
+ ui_thread_(BrowserThread::UI, &ui_loop_),
+ file_thread_(BrowserThread::FILE),
+ io_thread_(BrowserThread::IO) {
+ }
+
+ void OnImageLoaded(const gfx::Image& image) {
+ image_loaded_count_++;
+ if (quit_in_image_loaded_)
+ MessageLoop::current()->Quit();
+ image_ = image;
+ }
+
+ void WaitForImageLoad() {
+ quit_in_image_loaded_ = true;
+ MessageLoop::current()->Run();
+ quit_in_image_loaded_ = false;
+ }
+
+ int image_loaded_count() {
+ int result = image_loaded_count_;
+ image_loaded_count_ = 0;
+ return result;
+ }
+
+ scoped_refptr<Extension> CreateExtension(const char* name,
+ Extension::Location location) {
+ // Create and load an extension.
+ FilePath test_file;
+ if (!PathService::Get(chrome::DIR_TEST_DATA, &test_file)) {
+ EXPECT_FALSE(true);
+ return NULL;
+ }
+ test_file = test_file.AppendASCII("extensions")
+ .AppendASCII(name);
+ int error_code = 0;
+ std::string error;
+ JSONFileValueSerializer serializer(test_file.AppendASCII("app.json"));
+ scoped_ptr<DictionaryValue> valid_value(
+ static_cast<DictionaryValue*>(serializer.Deserialize(&error_code,
+ &error)));
+ EXPECT_EQ(0, error_code) << error;
+ if (error_code != 0)
+ return NULL;
+
+ EXPECT_TRUE(valid_value.get());
+ if (!valid_value.get())
+ return NULL;
+
+ if (location == Extension::COMPONENT) {
+ if (!PathService::Get(chrome::DIR_RESOURCES, &test_file)) {
+ EXPECT_FALSE(true);
+ return NULL;
+ }
+ test_file = test_file.AppendASCII(name);
+ }
+ return Extension::Create(test_file, location, *valid_value,
+ Extension::NO_FLAGS, &error);
+ }
+
+ gfx::Image image_;
+
+ private:
+ virtual void SetUp() {
+ file_thread_.Start();
+ io_thread_.Start();
+ }
+
+ int image_loaded_count_;
+ bool quit_in_image_loaded_;
+ MessageLoop ui_loop_;
+ content::TestBrowserThread ui_thread_;
+ content::TestBrowserThread file_thread_;
+ content::TestBrowserThread io_thread_;
+};
+
+// Tests loading an image works correctly.
+TEST_F(ImageLoaderTest, LoadImage) {
+ scoped_refptr<Extension> extension(CreateExtension(
+ "image_loading_tracker", Extension::INVALID));
+ ASSERT_TRUE(extension.get() != NULL);
+
+ ExtensionResource image_resource =
+ extension->GetIconResource(extension_misc::EXTENSION_ICON_SMALLISH,
+ ExtensionIconSet::MATCH_EXACTLY);
+ gfx::Size max_size(extension_misc::EXTENSION_ICON_SMALLISH,
+ extension_misc::EXTENSION_ICON_SMALLISH);
+ ImageLoader loader;
+ loader.LoadImageAsync(extension.get(),
+ image_resource,
+ max_size,
+ base::Bind(&ImageLoaderTest::OnImageLoaded,
+ base::Unretained(this)));
+
+ // The image isn't cached, so we should not have received notification.
+ EXPECT_EQ(0, image_loaded_count());
+
+ WaitForImageLoad();
+
+ // We should have gotten the image.
+ EXPECT_EQ(1, image_loaded_count());
+
+ // Check that the image was loaded.
+ EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH,
+ image_.ToSkBitmap()->width());
+}
+
+// Tests deleting an extension while waiting for the image to load doesn't cause
+// problems.
+TEST_F(ImageLoaderTest, DeleteExtensionWhileWaitingForCache) {
+ scoped_refptr<Extension> extension(CreateExtension(
+ "image_loading_tracker", Extension::INVALID));
+ ASSERT_TRUE(extension.get() != NULL);
+
+ ExtensionResource image_resource =
+ extension->GetIconResource(extension_misc::EXTENSION_ICON_SMALLISH,
+ ExtensionIconSet::MATCH_EXACTLY);
+ gfx::Size max_size(extension_misc::EXTENSION_ICON_SMALLISH,
+ extension_misc::EXTENSION_ICON_SMALLISH);
+ ImageLoader loader;
+ std::set<int> sizes;
+ sizes.insert(extension_misc::EXTENSION_ICON_SMALLISH);
+ loader.LoadImageAsync(extension.get(),
+ image_resource,
+ max_size,
+ base::Bind(&ImageLoaderTest::OnImageLoaded,
+ base::Unretained(this)));
+
+ // The image isn't cached, so we should not have received notification.
+ EXPECT_EQ(0, image_loaded_count());
+
+ // Send out notification the extension was uninstalled.
+ extensions::UnloadedExtensionInfo details(extension.get(),
+ extension_misc::UNLOAD_REASON_UNINSTALL);
+ content::NotificationService::current()->Notify(
+ chrome::NOTIFICATION_EXTENSION_UNLOADED,
+ content::NotificationService::AllSources(),
+ content::Details<extensions::UnloadedExtensionInfo>(&details));
+
+ // Chuck the extension, that way if anyone tries to access it we should crash
+ // or get valgrind errors.
+ extension = NULL;
+
+ WaitForImageLoad();
+
+ // Even though we deleted the extension, we should still get the image.
+ // We should still have gotten the image.
+ EXPECT_EQ(1, image_loaded_count());
+
+ // Check that the image was loaded.
+ EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH,
+ image_.ToSkBitmap()->width());
+}
+
+// Tests loading multiple dimensions of the same image.
+TEST_F(ImageLoaderTest, MultipleImages) {
+ scoped_refptr<Extension> extension(CreateExtension(
+ "image_loading_tracker", Extension::INVALID));
+ ASSERT_TRUE(extension.get() != NULL);
+
+ std::vector<ImageLoader::ImageRepresentation> info_list;
+ int sizes[] = {extension_misc::EXTENSION_ICON_SMALLISH,
+ extension_misc::EXTENSION_ICON_BITTY};
+ for (size_t i = 0; i < arraysize(sizes); ++i) {
+ ExtensionResource resource =
+ extension->GetIconResource(sizes[i], ExtensionIconSet::MATCH_EXACTLY);
+ info_list.push_back(ImageLoader::ImageRepresentation(
+ resource,
+ ImageLoader::ImageRepresentation::RESIZE_WHEN_LARGER,
+ gfx::Size(sizes[i], sizes[i]),
+ ui::SCALE_FACTOR_NONE));
+ }
+
+ ImageLoader loader;
+ loader.LoadImagesAsync(extension.get(), info_list,
+ base::Bind(&ImageLoaderTest::OnImageLoaded,
+ base::Unretained(this)));
+
+ // The image isn't cached, so we should not have received notification.
+ EXPECT_EQ(0, image_loaded_count());
+
+ WaitForImageLoad();
+
+ // We should have gotten the image.
+ EXPECT_EQ(1, image_loaded_count());
+
+ // Check that all images were loaded.
+ std::vector<gfx::ImageSkiaRep> image_reps =
+ image_.ToImageSkia()->image_reps();
+ ASSERT_EQ(2u, image_reps.size());
+ const gfx::ImageSkiaRep* img_rep1 = &image_reps[0];
+ const gfx::ImageSkiaRep* img_rep2 = &image_reps[1];
+ if (img_rep1->pixel_width() > img_rep2->pixel_width()) {
+ std::swap(img_rep1, img_rep2);
+ }
+ EXPECT_EQ(extension_misc::EXTENSION_ICON_BITTY,
+ img_rep1->pixel_width());
+ EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH,
+ img_rep2->pixel_width());
+}
+
+// Tests IsComponentExtensionResource function.
+TEST_F(ImageLoaderTest, IsComponentExtensionResource) {
+ scoped_refptr<Extension> extension(CreateExtension(
+ "file_manager", Extension::COMPONENT));
+ ASSERT_TRUE(extension.get() != NULL);
+
+ ExtensionResource resource =
+ extension->GetIconResource(extension_misc::EXTENSION_ICON_BITTY,
+ ExtensionIconSet::MATCH_EXACTLY);
+
+#if defined(FILE_MANAGER_EXTENSION)
+ int resource_id;
+ ASSERT_EQ(true,
+ ImageLoader::IsComponentExtensionResource(extension.get(),
+ resource.relative_path(),
+ &resource_id));
+ ASSERT_EQ(IDR_FILE_MANAGER_ICON_16, resource_id);
+#endif
+}
diff --git a/chrome/browser/extensions/image_loading_tracker.cc b/chrome/browser/extensions/image_loading_tracker.cc
index 7dc4773..cfd9209 100644
--- a/chrome/browser/extensions/image_loading_tracker.cc
+++ b/chrome/browser/extensions/image_loading_tracker.cc
@@ -9,20 +9,16 @@
#include "base/bind.h"
#include "base/file_util.h"
-#include "base/path_service.h"
#include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/extensions/image_loader.h"
#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
#include "chrome/common/chrome_notification_types.h"
-#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_resource.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
-#include "grit/component_extension_resources_map.h"
-#include "grit/chrome_unscaled_resources.h"
-#include "grit/theme_resources.h"
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/resource/resource_bundle.h"
@@ -309,68 +305,14 @@ void ImageLoadingTracker::LoadImages(
loader_ = new ImageLoader(this);
int resource_id = -1;
- if (IsComponentExtensionResource(extension, it->resource.relative_path(),
- &resource_id))
+ if (extensions::ImageLoader::IsComponentExtensionResource(
+ extension, it->resource.relative_path(), &resource_id))
loader_->LoadResource(*it, id, resource_id);
else
loader_->LoadImage(*it, id);
}
}
-bool ImageLoadingTracker::IsComponentExtensionResource(
- const Extension* extension,
- const FilePath& resource_path,
- int* resource_id) {
- static const GritResourceMap kExtraComponentExtensionResources[] = {
- {"web_store/webstore_icon_128.png", IDR_WEBSTORE_ICON},
- {"web_store/webstore_icon_16.png", IDR_WEBSTORE_ICON_16},
- {"chrome_app/product_logo_128.png", IDR_PRODUCT_LOGO_128},
- {"chrome_app/product_logo_16.png", IDR_PRODUCT_LOGO_16},
- {"settings_app/settings_app_icon_128.png", IDR_SETTINGS_APP_ICON_128},
- {"settings_app/settings_app_icon_16.png", IDR_SETTINGS_APP_ICON_16},
- };
- static const size_t kExtraComponentExtensionResourcesSize =
- arraysize(kExtraComponentExtensionResources);
-
- if (extension->location() != Extension::COMPONENT)
- return false;
-
- FilePath directory_path = extension->path();
- FilePath resources_dir;
- FilePath relative_path;
- if (!PathService::Get(chrome::DIR_RESOURCES, &resources_dir) ||
- !resources_dir.AppendRelativePath(directory_path, &relative_path)) {
- return false;
- }
- relative_path = relative_path.Append(resource_path);
- relative_path = relative_path.NormalizePathSeparators();
-
- // TODO(tc): Make a map of FilePath -> resource ids so we don't have to
- // covert to FilePaths all the time. This will be more useful as we add
- // more resources.
- for (size_t i = 0; i < kComponentExtensionResourcesSize; ++i) {
- FilePath resource_path =
- FilePath().AppendASCII(kComponentExtensionResources[i].name);
- resource_path = resource_path.NormalizePathSeparators();
-
- if (relative_path == resource_path) {
- *resource_id = kComponentExtensionResources[i].value;
- return true;
- }
- }
- for (size_t i = 0; i < kExtraComponentExtensionResourcesSize; ++i) {
- FilePath resource_path =
- FilePath().AppendASCII(kExtraComponentExtensionResources[i].name);
- resource_path = resource_path.NormalizePathSeparators();
-
- if (relative_path == resource_path) {
- *resource_id = kExtraComponentExtensionResources[i].value;
- return true;
- }
- }
- return false;
-}
-
void ImageLoadingTracker::OnBitmapLoaded(
const SkBitmap* bitmap,
const ImageRepresentation& image_info,
diff --git a/chrome/browser/extensions/image_loading_tracker.h b/chrome/browser/extensions/image_loading_tracker.h
index 5eefcd1..f820cda 100644
--- a/chrome/browser/extensions/image_loading_tracker.h
+++ b/chrome/browser/extensions/image_loading_tracker.h
@@ -122,14 +122,6 @@ class ImageLoadingTracker : public content::NotificationObserver {
// OnImageLoaded() the next time LoadImage() is invoked.
int next_id() const { return next_id_; }
- // Checks whether image is a component extension resource. Returns false
- // if a given |resource| does not have a corresponding image in bundled
- // resources. Otherwise fills |resource_id|.
- static bool IsComponentExtensionResource(
- const extensions::Extension* extension,
- const FilePath& resource_path,
- int* resource_id);
-
private:
// Information for pending resource load operation for one or more image
// representations.
diff --git a/chrome/browser/extensions/image_loading_tracker_unittest.cc b/chrome/browser/extensions/image_loading_tracker_unittest.cc
index 220c5c0..5754d94 100644
--- a/chrome/browser/extensions/image_loading_tracker_unittest.cc
+++ b/chrome/browser/extensions/image_loading_tracker_unittest.cc
@@ -244,24 +244,3 @@ TEST_F(ImageLoadingTrackerTest, MultipleImages) {
EXPECT_EQ(extension_misc::EXTENSION_ICON_SMALLISH,
img_rep2->pixel_width());
}
-
-// Tests IsComponentExtensionResource function.
-TEST_F(ImageLoadingTrackerTest, IsComponentExtensionResource) {
- scoped_refptr<Extension> extension(CreateExtension(
- "file_manager", Extension::COMPONENT));
- ASSERT_TRUE(extension.get() != NULL);
-
- ExtensionResource resource =
- extension->GetIconResource(extension_misc::EXTENSION_ICON_BITTY,
- ExtensionIconSet::MATCH_EXACTLY);
-
-#if defined(FILE_MANAGER_EXTENSION)
- ImageLoadingTracker loader(this);
- int resource_id;
- ASSERT_EQ(true,
- loader.IsComponentExtensionResource(extension.get(),
- resource.relative_path(),
- &resource_id));
- ASSERT_EQ(IDR_FILE_MANAGER_ICON_16, resource_id);
-#endif
-}
diff --git a/chrome/browser/extensions/navigation_observer.h b/chrome/browser/extensions/navigation_observer.h
index 480f983..acf78ad 100644
--- a/chrome/browser/extensions/navigation_observer.h
+++ b/chrome/browser/extensions/navigation_observer.h
@@ -10,6 +10,7 @@
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/extensions/extension_install_prompt.h"
+#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
class Profile;
diff --git a/chrome/browser/media/media_stream_capture_indicator.cc b/chrome/browser/media/media_stream_capture_indicator.cc
index 244235c..87266ac 100644
--- a/chrome/browser/media/media_stream_capture_indicator.cc
+++ b/chrome/browser/media/media_stream_capture_indicator.cc
@@ -11,6 +11,7 @@
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/image_loader.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/status_icons/status_icon.h"
#include "chrome/browser/status_icons/status_tray.h"
@@ -125,7 +126,7 @@ MediaStreamCaptureIndicator::MediaStreamCaptureIndicator()
mic_image_(NULL),
camera_image_(NULL),
balloon_image_(NULL),
- request_index_(0) {
+ should_show_balloon_(false) {
}
MediaStreamCaptureIndicator::~MediaStreamCaptureIndicator() {
@@ -228,7 +229,6 @@ void MediaStreamCaptureIndicator::CreateStatusTray() {
status_icon_ = status_tray->CreateStatusIcon();
EnsureStatusTrayIconResources();
- EnsureImageLoadingTracker();
}
void MediaStreamCaptureIndicator::EnsureStatusTrayIconResources() {
@@ -267,14 +267,23 @@ void MediaStreamCaptureIndicator::ShowBalloon(
const extensions::Extension* extension =
GetExtension(render_process_id, render_view_id);
if (extension) {
- pending_messages_[request_index_++] =
+ string16 message =
l10n_util::GetStringFUTF16(message_id,
UTF8ToUTF16(extension->name()));
- tracker_->LoadImage(
+
+ WebContents* web_contents = tab_util::GetWebContentsByID(
+ render_process_id, render_view_id);
+
+ Profile* profile =
+ Profile::FromBrowserContext(web_contents->GetBrowserContext());
+
+ should_show_balloon_ = true;
+ extensions::ImageLoader::Get(profile)->LoadImageAsync(
extension,
extension->GetIconResource(32, ExtensionIconSet::MATCH_BIGGER),
gfx::Size(32, 32),
- ImageLoadingTracker::CACHE);
+ base::Bind(&MediaStreamCaptureIndicator::OnImageLoaded,
+ this, message));
return;
}
@@ -285,12 +294,10 @@ void MediaStreamCaptureIndicator::ShowBalloon(
}
void MediaStreamCaptureIndicator::OnImageLoaded(
- const gfx::Image& image,
- const std::string& extension_id,
- int index) {
- string16 message;
- message.swap(pending_messages_[index]);
- pending_messages_.erase(index);
+ const string16& message,
+ const gfx::Image& image) {
+ if (!should_show_balloon_)
+ return;
const gfx::ImageSkia* image_skia = !image.IsEmpty() ? image.ToImageSkia() :
ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
@@ -302,8 +309,8 @@ void MediaStreamCaptureIndicator::Hide() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(tabs_.empty());
- // We have to destroy |tracker_| on the UI thread.
- tracker_.reset();
+ // Make sure images that finish loading don't cause a balloon to be shown.
+ should_show_balloon_ = false;
if (!status_icon_)
return;
@@ -468,13 +475,3 @@ bool MediaStreamCaptureIndicator::IsProcessCapturing(int render_process_id,
return false;
return (iter->audio_ref_count > 0 || iter->video_ref_count > 0);
}
-
-void MediaStreamCaptureIndicator::EnsureImageLoadingTracker() {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- if (tracker_.get())
- return;
-
- tracker_.reset(new ImageLoadingTracker(this));
- pending_messages_.clear();
- request_index_ = 0;
-}
diff --git a/chrome/browser/media/media_stream_capture_indicator.h b/chrome/browser/media/media_stream_capture_indicator.h
index 6b6becc..8696f91 100644
--- a/chrome/browser/media/media_stream_capture_indicator.h
+++ b/chrome/browser/media/media_stream_capture_indicator.h
@@ -10,7 +10,6 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/extensions/image_loading_tracker.h"
#include "content/public/common/media_stream_request.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/gfx/image/image_skia.h"
@@ -22,8 +21,7 @@ class StatusTray;
// is deleted.
class MediaStreamCaptureIndicator
: public base::RefCountedThreadSafe<MediaStreamCaptureIndicator>,
- public ui::SimpleMenuModel::Delegate,
- public ImageLoadingTracker::Observer {
+ public ui::SimpleMenuModel::Delegate {
public:
MediaStreamCaptureIndicator();
@@ -48,10 +46,8 @@ class MediaStreamCaptureIndicator
// Returns true if the render process is capturing media.
bool IsProcessCapturing(int render_process_id, int render_view_id) const;
- // ImageLoadingTracker::Observer implementation.
- virtual void OnImageLoaded(const gfx::Image& image,
- const std::string& extension_id,
- int index) OVERRIDE;
+ // ImageLoader callback.
+ void OnImageLoaded(const string16& message, const gfx::Image& image);
private:
// Struct to store the usage information of the capture devices for each tab.
@@ -131,9 +127,6 @@ class MediaStreamCaptureIndicator
// UpdateStatusTrayIconContextMenu().
void UpdateStatusTrayIconDisplay(bool audio, bool video);
- // Initializes image loading state.
- void EnsureImageLoadingTracker();
-
// Reference to our status icon - owned by the StatusTray. If null,
// the platform doesn't support status icons.
StatusIcon* status_icon_;
@@ -147,13 +140,7 @@ class MediaStreamCaptureIndicator
typedef std::vector<CaptureDeviceTab> CaptureDeviceTabs;
CaptureDeviceTabs tabs_;
- // Tracks the load of extension icons.
- scoped_ptr<ImageLoadingTracker> tracker_;
- // The messages to display when extension images are loaded. The index
- // corresponds to the index of the associated LoadImage request.
- std::map<int, string16> pending_messages_;
- // Tracks the number of requests to |tracker_|.
- int request_index_;
+ bool should_show_balloon_;
};
#endif // CHROME_BROWSER_MEDIA_MEDIA_STREAM_CAPTURE_INDICATOR_H_
diff --git a/chrome/browser/ui/webui/extensions/extension_icon_source.cc b/chrome/browser/ui/webui/extensions/extension_icon_source.cc
index d2704717..78f360d 100644
--- a/chrome/browser/ui/webui/extensions/extension_icon_source.cc
+++ b/chrome/browser/ui/webui/extensions/extension_icon_source.cc
@@ -15,6 +15,7 @@
#include "base/threading/thread.h"
#include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/image_loader.h"
#include "chrome/browser/favicon/favicon_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
@@ -57,9 +58,7 @@ SkBitmap* ToBitmap(const unsigned char* data, size_t size) {
ExtensionIconSource::ExtensionIconSource(Profile* profile)
: DataSource(chrome::kChromeUIExtensionIconHost, MessageLoop::current()),
- profile_(profile),
- next_tracker_id_(0) {
- tracker_.reset(new ImageLoadingTracker(this));
+ profile_(profile) {
}
struct ExtensionIconSource::ExtensionIconRequest {
@@ -188,11 +187,10 @@ void ExtensionIconSource::LoadDefaultImage(int request_id) {
void ExtensionIconSource::LoadExtensionImage(const ExtensionResource& icon,
int request_id) {
ExtensionIconRequest* request = GetData(request_id);
- tracker_map_[next_tracker_id_++] = request_id;
- tracker_->LoadImage(request->extension,
- icon,
- gfx::Size(request->size, request->size),
- ImageLoadingTracker::DONT_CACHE);
+ extensions::ImageLoader::Get(profile_)->LoadImageAsync(
+ request->extension, icon,
+ gfx::Size(request->size, request->size),
+ base::Bind(&ExtensionIconSource::OnImageLoaded, this, request_id));
}
void ExtensionIconSource::LoadFaviconImage(int request_id) {
@@ -243,12 +241,8 @@ void ExtensionIconSource::OnFaviconDataAvailable(
}
}
-void ExtensionIconSource::OnImageLoaded(const gfx::Image& image,
- const std::string& extension_id,
- int index) {
- int request_id = tracker_map_[index];
- tracker_map_.erase(tracker_map_.find(index));
-
+void ExtensionIconSource::OnImageLoaded(int request_id,
+ const gfx::Image& image) {
if (image.IsEmpty())
LoadIconFailed(request_id);
else
diff --git a/chrome/browser/ui/webui/extensions/extension_icon_source.h b/chrome/browser/ui/webui/extensions/extension_icon_source.h
index f5f445e..1a05224 100644
--- a/chrome/browser/ui/webui/extensions/extension_icon_source.h
+++ b/chrome/browser/ui/webui/extensions/extension_icon_source.h
@@ -9,10 +9,10 @@
#include <string>
#include "base/basictypes.h"
-#include "chrome/browser/extensions/image_loading_tracker.h"
#include "chrome/browser/favicon/favicon_service.h"
#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
#include "chrome/common/extensions/extension_icon_set.h"
+#include "chrome/common/extensions/extension_resource.h"
#include "third_party/skia/include/core/SkBitmap.h"
class ExtensionIconSet;
@@ -48,8 +48,7 @@ class Extension;
// 2) If a 16px icon was requested, the favicon for extension's launch URL.
// 3) The default extension / application icon if there are still no matches.
//
-class ExtensionIconSource : public ChromeURLDataManager::DataSource,
- public ImageLoadingTracker::Observer {
+class ExtensionIconSource : public ChromeURLDataManager::DataSource {
public:
explicit ExtensionIconSource(Profile* profile);
@@ -109,10 +108,8 @@ class ExtensionIconSource : public ChromeURLDataManager::DataSource,
FaviconService::Handle request_handle,
const history::FaviconBitmapResult& bitmap_result);
- // ImageLoadingTracker::Observer
- virtual void OnImageLoaded(const gfx::Image& image,
- const std::string& extension_id,
- int id) OVERRIDE;
+ // ImageLoader callback
+ void OnImageLoaded(int request_id, const gfx::Image& image);
// Called when the extension doesn't have an icon. We fall back to multiple
// sources, using the following order:
@@ -151,10 +148,6 @@ class ExtensionIconSource : public ChromeURLDataManager::DataSource,
// Maps request_ids to ExtensionIconRequests.
std::map<int, ExtensionIconRequest*> request_map_;
- scoped_ptr<ImageLoadingTracker> tracker_;
-
- int next_tracker_id_;
-
scoped_ptr<SkBitmap> default_app_data_;
scoped_ptr<SkBitmap> default_extension_data_;
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index f48d260..62a398e0 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -532,6 +532,10 @@
'browser/extensions/external_registry_loader_win.h',
'browser/extensions/file_reader.cc',
'browser/extensions/file_reader.h',
+ 'browser/extensions/image_loader.cc',
+ 'browser/extensions/image_loader.h',
+ 'browser/extensions/image_loader_factory.cc',
+ 'browser/extensions/image_loader_factory.h',
'browser/extensions/image_loading_tracker.cc',
'browser/extensions/image_loading_tracker.h',
'browser/extensions/installed_loader.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 46f9be2..8fd1746 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -730,6 +730,7 @@
'browser/extensions/page_action_controller_unittest.cc',
'browser/extensions/permissions_updater_unittest.cc',
'browser/extensions/file_reader_unittest.cc',
+ 'browser/extensions/image_loader_unittest.cc',
'browser/extensions/image_loading_tracker_unittest.cc',
'browser/extensions/key_identifier_conversion_views_unittest.cc',
'browser/extensions/management_policy_unittest.cc',