Index: chrome/browser/extensions/image_loading_tracker.cc |
diff --git a/chrome/browser/extensions/image_loading_tracker.cc b/chrome/browser/extensions/image_loading_tracker.cc |
index 02fd19bce02b7f5af03ea567368a1296649b24ed..2500988c7494febe8296a60196b59577994e5cb0 100644 |
--- a/chrome/browser/extensions/image_loading_tracker.cc |
+++ b/chrome/browser/extensions/image_loading_tracker.cc |
@@ -20,28 +20,78 @@ |
#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" |
#include "ui/gfx/image/image.h" |
-#include "ui/gfx/image/image_skia.h" |
#include "ui/gfx/image/image_skia_rep.h" |
#include "webkit/glue/image_decoder.h" |
using content::BrowserThread; |
using extensions::Extension; |
+namespace { |
+ |
+struct ComponentExtensionResource { |
+ const char* extension_id; |
+ const int resource_id; |
+}; |
+ |
+const ComponentExtensionResource kSpecialComponentExtensionResources[] = { |
+ { extension_misc::kWebStoreAppId, IDR_WEBSTORE_ICON }, |
+ { extension_misc::kChromeAppId, IDR_PRODUCT_LOGO_128 }, |
+}; |
+ |
+// Finds special component extension resource id for given extension id. |
+bool FindSpecialExtensionResourceId(const std::string& extension_id, |
+ int* out_resource_id) { |
+ for (size_t i = 0; i < arraysize(kSpecialComponentExtensionResources); ++i) { |
+ if (extension_id == kSpecialComponentExtensionResources[i].extension_id) { |
+ if (out_resource_id) |
+ *out_resource_id = kSpecialComponentExtensionResources[i].resource_id; |
+ return true; |
+ } |
+ } |
+ |
+ return false; |
+} |
+ |
+bool ShouldResizeImageRepresentation( |
+ ImageLoadingTracker::ImageRepresentation::ResizeCondition resize_method, |
+ const gfx::Size& decoded_size, |
+ const gfx::Size& desired_size) { |
+ switch (resize_method) { |
+ case ImageLoadingTracker::ImageRepresentation::ALWAYS_RESIZE: |
+ return decoded_size != desired_size; |
+ case ImageLoadingTracker::ImageRepresentation::RESIZE_WHEN_LARGER: |
+ return decoded_size.width() > desired_size.width() || |
+ decoded_size.height() > desired_size.height(); |
+ default: |
+ NOTREACHED(); |
+ return false; |
+ } |
+} |
+ |
+} // namespace |
+ |
//////////////////////////////////////////////////////////////////////////////// |
// ImageLoadingTracker::Observer |
ImageLoadingTracker::Observer::~Observer() {} |
//////////////////////////////////////////////////////////////////////////////// |
-// ImageLoadingTracker::ImageInfo |
+// ImageLoadingTracker::ImageRepresentation |
-ImageLoadingTracker::ImageInfo::ImageInfo( |
- const ExtensionResource& resource, gfx::Size max_size) |
- : resource(resource), max_size(max_size) { |
+ImageLoadingTracker::ImageRepresentation::ImageRepresentation( |
+ const ExtensionResource& resource, |
+ ResizeCondition resize_method, |
+ const gfx::Size& desired_size, |
+ ui::ScaleFactor scale_factor) |
+ : resource(resource), |
+ resize_method(resize_method), |
+ desired_size(desired_size), |
+ scale_factor(scale_factor) { |
} |
-ImageLoadingTracker::ImageInfo::~ImageInfo() { |
+ImageLoadingTracker::ImageRepresentation::~ImageRepresentation() { |
} |
//////////////////////////////////////////////////////////////////////////////// |
@@ -58,8 +108,8 @@ ImageLoadingTracker::PendingLoadInfo::~PendingLoadInfo() {} |
//////////////////////////////////////////////////////////////////////////////// |
// ImageLoadingTracker::ImageLoader |
-// A RefCounted class for loading images on the File thread and reporting back |
-// on the UI thread. |
+// A RefCounted class for loading bitmaps/image reps on the File thread and |
+// reporting back on the UI thread. |
class ImageLoadingTracker::ImageLoader |
: public base::RefCountedThreadSafe<ImageLoader> { |
public: |
@@ -76,106 +126,104 @@ class ImageLoadingTracker::ImageLoader |
} |
// Instructs the loader to load a task on the File thread. |
- void LoadImage(const ExtensionResource& resource, |
- const gfx::Size& max_size, |
- int id) { |
- DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ void LoadImage(const ImageRepresentation& image_info, int id) { |
+ DCHECK(BrowserThread::CurrentlyOn(callback_thread_id_)); |
BrowserThread::PostTask( |
BrowserThread::FILE, FROM_HERE, |
- base::Bind(&ImageLoader::LoadOnFileThread, this, resource, |
- max_size, id)); |
+ base::Bind(&ImageLoader::LoadOnFileThread, this, image_info, id)); |
} |
- void LoadOnFileThread(const ExtensionResource& resource, |
- const gfx::Size& max_size, |
- int id) { |
+ void LoadOnFileThread(const ImageRepresentation& image_info, int id) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
// Read the file from disk. |
std::string file_contents; |
- FilePath path = resource.GetFilePath(); |
+ FilePath path = image_info.resource.GetFilePath(); |
if (path.empty() || !file_util::ReadFileToString(path, &file_contents)) { |
- ReportBack(NULL, resource, gfx::Size(), id); |
+ ReportBack(NULL, image_info, gfx::Size(), id, false); |
return; |
} |
- // Decode the image using WebKit's image decoder. |
+ // Decode the bitmap using WebKit's image decoder. |
const unsigned char* data = |
reinterpret_cast<const unsigned char*>(file_contents.data()); |
webkit_glue::ImageDecoder decoder; |
scoped_ptr<SkBitmap> decoded(new SkBitmap()); |
- // Note: This class only decodes images from extension resources. Chrome |
+ // 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 images here that were generated by Chrome. |
+ // Chrome is therefore decoding bitmaps here that were generated by Chrome. |
*decoded = decoder.Decode(data, file_contents.length()); |
if (decoded->empty()) { |
- ReportBack(NULL, resource, gfx::Size(), id); |
+ ReportBack(NULL, image_info, gfx::Size(), id, false); |
return; // Unable to decode. |
} |
gfx::Size original_size(decoded->width(), decoded->height()); |
- |
- if (decoded->width() > max_size.width() || |
- decoded->height() > max_size.height()) { |
- // The bitmap is too big, re-sample. |
+ if (ShouldResizeImageRepresentation(image_info.resize_method, |
+ original_size, |
+ image_info.desired_size)) { |
*decoded = skia::ImageOperations::Resize( |
*decoded, skia::ImageOperations::RESIZE_LANCZOS3, |
- max_size.width(), max_size.height()); |
+ image_info.desired_size.width(), image_info.desired_size.height()); |
} |
- ReportBack(decoded.release(), resource, original_size, id); |
+ ReportBack(decoded.release(), image_info, original_size, id, |
+ true /* delete bitmap */); |
} |
// Instructs the loader to load a resource on the File thread. |
- void LoadResource(const ExtensionResource& resource, |
- const gfx::Size& max_size, |
+ void LoadResource(const ImageRepresentation& image_info, |
int id, |
int resource_id) { |
- DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ DCHECK(BrowserThread::CurrentlyOn(callback_thread_id_)); |
BrowserThread::PostTask( |
BrowserThread::FILE, FROM_HERE, |
- base::Bind(&ImageLoader::LoadResourceOnFileThread, this, resource, |
- max_size, id, resource_id)); |
+ base::Bind(&ImageLoader::LoadResourceOnFileThread, this, image_info, |
+ id, resource_id)); |
} |
- void LoadResourceOnFileThread(const ExtensionResource& resource, |
- const gfx::Size& max_size, |
+ void LoadResourceOnFileThread(const ImageRepresentation& image_info, |
int id, |
int resource_id) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
- SkBitmap* image = ExtensionIconSource::LoadImageByResourceId( |
- resource_id); |
- ReportBack(image, resource, max_size, id); |
+ const SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetImageNamed( |
+ resource_id).ToSkBitmap(); |
+ ReportBack(bitmap, image_info, image_info.desired_size, id, |
+ false /* don't delete bitmap */); |
} |
- void ReportBack(SkBitmap* image, const ExtensionResource& resource, |
- const gfx::Size& original_size, int id) { |
+ void ReportBack(const SkBitmap* bitmap, const ImageRepresentation& image_info, |
+ const gfx::Size& original_size, int id, bool delete_bitmap) { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
BrowserThread::PostTask( |
callback_thread_id_, FROM_HERE, |
- base::Bind(&ImageLoader::ReportOnUIThread, this, |
- image, resource, original_size, id)); |
+ base::Bind(&ImageLoader::ReportOnCallingThread, this, |
+ bitmap, image_info, original_size, id, delete_bitmap)); |
} |
- void ReportOnUIThread(SkBitmap* image, const ExtensionResource& resource, |
- const gfx::Size& original_size, int id) { |
- DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
+ void ReportOnCallingThread(const SkBitmap* bitmap, |
+ const ImageRepresentation& image_info, |
+ const gfx::Size& original_size, |
+ int id, |
+ bool delete_bitmap) { |
+ DCHECK(BrowserThread::CurrentlyOn(callback_thread_id_)); |
if (tracker_) |
- tracker_->OnImageLoaded(image, resource, original_size, id, true); |
+ tracker_->OnBitmapLoaded(bitmap, image_info, original_size, id, true); |
- delete image; |
+ if (bitmap && delete_bitmap) |
+ delete bitmap; |
} |
private: |
friend class base::RefCountedThreadSafe<ImageLoader>; |
~ImageLoader() {} |
- // The tracker we are loading the image for. If NULL, it means the tracker is |
+ // The tracker we are loading the bitmap for. If NULL, it means the tracker is |
// no longer interested in the reply. |
ImageLoadingTracker* tracker_; |
@@ -206,14 +254,19 @@ void ImageLoadingTracker::LoadImage(const Extension* extension, |
const ExtensionResource& resource, |
const gfx::Size& max_size, |
CacheParam cache) { |
- std::vector<ImageInfo> info_list; |
- info_list.push_back(ImageInfo(resource, max_size)); |
+ std::vector<ImageRepresentation> info_list; |
+ info_list.push_back(ImageRepresentation( |
+ resource, |
+ ImageRepresentation::RESIZE_WHEN_LARGER, |
+ max_size, |
+ ui::SCALE_FACTOR_100P)); |
LoadImages(extension, info_list, cache); |
} |
-void ImageLoadingTracker::LoadImages(const Extension* extension, |
- const std::vector<ImageInfo>& info_list, |
- CacheParam cache) { |
+void ImageLoadingTracker::LoadImages( |
+ const Extension* extension, |
+ const std::vector<ImageRepresentation>& info_list, |
+ CacheParam cache) { |
PendingLoadInfo load_info; |
load_info.extension = extension; |
load_info.cache = cache; |
@@ -222,37 +275,32 @@ void ImageLoadingTracker::LoadImages(const Extension* extension, |
int id = next_id_++; |
load_map_[id] = load_info; |
- for (std::vector<ImageInfo>::const_iterator it = info_list.begin(); |
+ for (std::vector<ImageRepresentation>::const_iterator it = info_list.begin(); |
it != info_list.end(); ++it) { |
+ int resource_id = -1; |
+ |
// Load resources for special component extensions. |
- if (load_info.extension_id == extension_misc::kWebStoreAppId) { |
- if (!loader_) |
- loader_ = new ImageLoader(this); |
- loader_->LoadResource(it->resource, it->max_size, id, IDR_WEBSTORE_ICON); |
- continue; |
- } else if (load_info.extension_id == extension_misc::kChromeAppId) { |
+ if (FindSpecialExtensionResourceId(load_info.extension_id, &resource_id)) { |
if (!loader_) |
loader_ = new ImageLoader(this); |
- loader_->LoadResource(it->resource, |
- it->max_size, |
- id, |
- IDR_PRODUCT_LOGO_128); |
+ loader_->LoadResource(*it, id, resource_id); |
continue; |
} |
// If we don't have a path we don't need to do any further work, just |
// respond back. |
if (it->resource.relative_path().empty()) { |
- OnImageLoaded(NULL, it->resource, it->max_size, id, false); |
+ OnBitmapLoaded(NULL, *it, it->desired_size, id, false); |
continue; |
} |
DCHECK(extension->path() == it->resource.extension_root()); |
- // See if the extension has the image already. |
- if (extension->HasCachedImage(it->resource, it->max_size)) { |
- SkBitmap image = extension->GetCachedImage(it->resource, it->max_size); |
- OnImageLoaded(&image, it->resource, it->max_size, id, false); |
+ // See if the extension has the bitmap already. |
+ if (extension->HasCachedImage(it->resource, it->desired_size)) { |
+ SkBitmap bitmap = extension->GetCachedImage(it->resource, |
+ it->desired_size); |
+ OnBitmapLoaded(&bitmap, *it, it->desired_size, id, false); |
continue; |
} |
@@ -261,11 +309,10 @@ void ImageLoadingTracker::LoadImages(const Extension* extension, |
if (!loader_) |
loader_ = new ImageLoader(this); |
- int resource_id; |
if (IsComponentExtensionResource(extension, it->resource, resource_id)) |
- loader_->LoadResource(it->resource, it->max_size, id, resource_id); |
+ loader_->LoadResource(*it, id, resource_id); |
else |
- loader_->LoadImage(it->resource, it->max_size, id); |
+ loader_->LoadImage(*it, id); |
} |
} |
@@ -293,9 +340,9 @@ bool ImageLoadingTracker::IsComponentExtensionResource( |
return false; |
} |
-void ImageLoadingTracker::OnImageLoaded( |
- SkBitmap* image, |
- const ExtensionResource& resource, |
+void ImageLoadingTracker::OnBitmapLoaded( |
+ const SkBitmap* bitmap, |
+ const ImageRepresentation& image_info, |
const gfx::Size& original_size, |
int id, |
bool should_cache) { |
@@ -304,38 +351,33 @@ void ImageLoadingTracker::OnImageLoaded( |
PendingLoadInfo* info = &load_map_it->second; |
// Save the pending results. |
- DCHECK(info->pending_count > 0); |
+ DCHECK_GT(info->pending_count, 0u); |
info->pending_count--; |
- if (image) |
- info->bitmaps.push_back(*image); |
+ if (bitmap) { |
+ info->image_skia.AddRepresentation(gfx::ImageSkiaRep(*bitmap, |
+ image_info.scale_factor)); |
+ } |
- // Add to the extension's image cache if requested. |
+ // Add to the extension's bitmap cache if requested. |
DCHECK(info->cache != CACHE || info->extension); |
- if (should_cache && info->cache == CACHE && !resource.empty() && |
- !info->extension->HasCachedImage(resource, original_size)) { |
- info->extension->SetCachedImage(resource, image ? *image : SkBitmap(), |
+ if (should_cache && info->cache == CACHE && !image_info.resource.empty() && |
+ !info->extension->HasCachedImage(image_info.resource, original_size)) { |
+ info->extension->SetCachedImage(image_info.resource, |
+ bitmap ? *bitmap : SkBitmap(), |
original_size); |
} |
- // If all pending images are done then report back. |
+ // If all pending bitmaps are done then report back. |
if (info->pending_count == 0) { |
gfx::Image image; |
std::string extension_id = info->extension_id; |
- if (info->bitmaps.size() > 0) { |
- gfx::ImageSkia image_skia; |
- for (std::vector<SkBitmap>::const_iterator it = info->bitmaps.begin(); |
- it != info->bitmaps.end(); ++it) { |
- // TODO(pkotwicz): Do something better but ONLY when DIP is enabled. |
- image_skia.AddRepresentation( |
- gfx::ImageSkiaRep(*it, ui::SCALE_FACTOR_100P)); |
- } |
- image = gfx::Image(image_skia); |
- } |
+ if (!info->image_skia.empty()) |
+ image = gfx::Image(info->image_skia); |
load_map_.erase(load_map_it); |
- // ImageLoadingTracker might be deleted after the callback so don't |
+ // ImageLoadingTracker might be deleted after the callback so don't do |
// anything after this statement. |
observer_->OnImageLoaded(image, extension_id, id); |
} |
@@ -350,7 +392,7 @@ void ImageLoadingTracker::Observe(int type, |
content::Details<extensions::UnloadedExtensionInfo>(details)->extension; |
// Remove reference to this extension from all pending load entries. This |
- // ensures we don't attempt to cache the image when the load completes. |
+ // ensures we don't attempt to cache the bitmap when the load completes. |
for (LoadMap::iterator i = load_map_.begin(); i != load_map_.end(); ++i) { |
PendingLoadInfo* info = &i->second; |
if (info->extension == extension) { |