Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5769)

Unified Diff: chrome/browser/extensions/extension_icon_image.cc

Issue 10861034: Supply default icon to extension icon image. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/extension_icon_image.cc
diff --git a/chrome/browser/extensions/extension_icon_image.cc b/chrome/browser/extensions/extension_icon_image.cc
index dcd096815c03ab6c26653705b041539a73703acc..42aae616f37982220dadf4881a1e46d6d038a296 100644
--- a/chrome/browser/extensions/extension_icon_image.cc
+++ b/chrome/browser/extensions/extension_icon_image.cc
@@ -9,10 +9,48 @@
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/extensions/extension.h"
#include "content/public/browser/notification_service.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/image/canvas_image_source.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/size.h"
+/**
+ * The file contains extensions::IconImage implementation, which provides
Jeffrey Yasskin 2012/09/01 01:10:27 Shorter comments are better, all else equal, to pr
tbarzic 2012/09/04 21:07:09 Done.
+ * extension icons to be displayed in the UI.
+ * The icon provided by IconImage is ImageSkia icon defined with custom
+ * ImageSkiaSource. When a new image representation is requesetd from the image
Jeffrey Yasskin 2012/09/01 01:10:27 sp: requesetd
tbarzic 2012/09/04 21:07:09 Done.
+ * source the following happens:
+ * - If the extension doesn't have a icon resource needed for the image
Jeffrey Yasskin 2012/09/01 01:10:27 There's some complex behavior around which sizes a
tbarzic 2012/09/04 21:07:09 Done.
+ * representation, default icon's representation for the requested scale
+ * factor is returned by ImageSkiaSource. If the default icon is empty,
Jeffrey Yasskin 2012/09/01 01:10:27 You wind up saying the empty-default fallback 3 ti
tbarzic 2012/09/04 21:07:09 Done.
+ * transparent image representation is returned.
+ * - If the extension has the resource, IconImage tries to load it using
+ * ImageLoadingTracker.
+ * - |ImageLoaderTracker| may return both syncronously and asyncronously.
Jeffrey Yasskin 2012/09/01 01:10:27 sp: syncronously 2x
tbarzic 2012/09/04 21:07:09 Done.
+ * IconImage behaviour depends on this.
+ * 1. |ImageLoaderTracker| is synchronous.
+ * - If image representation resurce is successfully loaded, the
Jeffrey Yasskin 2012/09/01 01:10:27 sp: resurce
tbarzic 2012/09/04 21:07:09 Done.
+ * representation returned by ImageSkiaSource is created from the loaded
+ * bitmap.
+ * - If resource loading fails, ImageSkiaSource returns either default icon's
+ * representation, or a blank image representation; depending on whether the
+ * supplied default icon was non empty.
+ * 2. |ImageLoadingTracker| is asyncronous.
+ * - ImageSkiaSource will initially return transparent image resource of the
+ * desired size.
+ * - The image will be manually updated when the |ImageLoadingTracker|
Jeffrey Yasskin 2012/09/01 01:10:27 Nothing's manual in code. I think you mean that we
tbarzic 2012/09/04 21:07:09 Done.
+ * finishes.
+ * - If image resource is successfully loaded, the image is updated with the
+ * representation created from the loaded bitmap (the old representation is
+ * removed from the image). Also, the observer is notified the image has
+ * changed.
+ * - If resource load failed and non empty default icon was supplied, image
+ * is updated by the corresponding representatin from the default icon and
Jeffrey Yasskin 2012/09/01 01:10:27 sp: representatin
tbarzic 2012/09/04 21:07:09 Done.
+ * the obesrver is notifeid image has changed.
+ * - If resource load failed and an empty default icon was supplied, nothing
+ * is done. The image will keep initial, transparent representation.
+**/
namespace {
const int kMatchBiggerTreshold = 32;
@@ -29,6 +67,22 @@ ExtensionResource GetExtensionIconResource(
return extension->GetResource(path);
}
+class BlankImageSource : public gfx::CanvasImageSource {
+ public:
+ explicit BlankImageSource(const gfx::Size& size_in_dip)
+ : CanvasImageSource(size_in_dip, false) {
Jeffrey Yasskin 2012/09/01 01:10:27 I prefer writing something like /*is_opaque=*/fals
tbarzic 2012/09/04 21:07:09 yeah, I've started doing this, but I still occasio
+ }
+ virtual ~BlankImageSource() {}
+
+ private:
+ // gfx::CanvasImageSource overrides:
+ virtual void Draw(gfx::Canvas* canvas) OVERRIDE {
+ canvas->DrawColor(SkColorSetARGB(0, 0, 0, 0));
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(BlankImageSource);
+};
+
} // namespace
namespace extensions {
@@ -38,7 +92,7 @@ namespace extensions {
class IconImage::Source : public gfx::ImageSkiaSource {
public:
- explicit Source(IconImage* host);
+ Source(IconImage* host, const gfx::Size& size_in_dip);
virtual ~Source();
void ResetHost();
@@ -48,12 +102,23 @@ class IconImage::Source : public gfx::ImageSkiaSource {
virtual gfx::ImageSkiaRep GetImageForScale(
ui::ScaleFactor scale_factor) OVERRIDE;
+ // IconImage object that is hosting this image source. It is used to load
Jeffrey Yasskin 2012/09/01 01:10:27 Shorter: "Used to load images, possibly asynchrono
tbarzic 2012/09/04 21:07:09 Done.
+ // image representation for the extension icon.
+ // |host_| will be reset once the referenced icon image dies. Since |this|
+ // can outlive the IconImage, NULL check should be made on |host_| before
+ // using it.
IconImage* host_;
+ // Image whose representations will be used until |host_| load the real
+ // representations for the image.
+ gfx::ImageSkia blank_image_;
+
DISALLOW_COPY_AND_ASSIGN(Source);
};
-IconImage::Source::Source(IconImage* host) : host_(host) {
+IconImage::Source::Source(IconImage* host, const gfx::Size& size_in_dip)
+ : host_(host),
+ blank_image_(new BlankImageSource(size_in_dip), size_in_dip) {
}
IconImage::Source::~Source() {
@@ -65,9 +130,14 @@ void IconImage::Source::ResetHost() {
gfx::ImageSkiaRep IconImage::Source::GetImageForScale(
ui::ScaleFactor scale_factor) {
+ gfx::ImageSkiaRep representation;
if (host_)
- host_->LoadImageForScaleFactor(scale_factor);
- return gfx::ImageSkiaRep();
+ representation = host_->LoadImageForScaleFactor(scale_factor);
+
+ if (!representation.is_null())
+ return representation;
+
+ return blank_image_.GetRepresentation(scale_factor);
}
////////////////////////////////////////////////////////////////////////////////
@@ -77,31 +147,31 @@ IconImage::IconImage(
const Extension* extension,
const ExtensionIconSet& icon_set,
int resource_size_in_dip,
+ const gfx::ImageSkia& default_icon,
Observer* observer)
: extension_(extension),
icon_set_(icon_set),
resource_size_in_dip_(resource_size_in_dip),
- desired_size_in_dip_(resource_size_in_dip, resource_size_in_dip),
observer_(observer),
source_(NULL),
+ default_icon_(default_icon),
ALLOW_THIS_IN_INITIALIZER_LIST(tracker_(this)) {
- source_ = new Source(this);
- image_skia_ = gfx::ImageSkia(source_, desired_size_in_dip_);
+ gfx::Size resource_size(resource_size_in_dip, resource_size_in_dip);
+ source_ = new Source(this, resource_size);
+ image_skia_ = gfx::ImageSkia(source_, resource_size);
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
content::NotificationService::AllSources());
}
IconImage::~IconImage() {
Jeffrey Yasskin 2012/09/01 01:10:27 This still needs to call ResetHost(), right? If th
tbarzic 2012/09/04 21:07:09 jeez, I'm sometimes amazed with things I do on Fri
- // |source_| could be NULL if resource does not exist.
- if (source_)
- source_->ResetHost();
}
-void IconImage::LoadImageForScaleFactor(ui::ScaleFactor scale_factor) {
+gfx::ImageSkiaRep IconImage::LoadImageForScaleFactor(
+ ui::ScaleFactor scale_factor) {
// Do nothing if extension is unloaded.
if (!extension_)
- return;
+ return gfx::ImageSkiaRep();
const float scale = ui::GetScaleFactorScale(scale_factor);
const int resource_size_in_pixel =
@@ -120,48 +190,68 @@ void IconImage::LoadImageForScaleFactor(ui::ScaleFactor scale_factor) {
resource_size_in_pixel, ExtensionIconSet::MATCH_SMALLER);
}
- // If there is no resource found, bail out and notify observer of failure.
- if (resource.empty()) {
- if (observer_)
- observer_->OnIconImageLoadFailed(this, scale_factor);
- return;
- }
+ // If there is no resource found, return default icon.
+ if (resource.empty())
+ return default_icon_.GetRepresentation(scale_factor);
int id = tracker_.next_id();
- load_map_[id] = scale_factor;
+ load_map_[id].scale_factor = scale_factor;
+ load_map_[id].is_async = false;
std::vector<ImageLoadingTracker::ImageRepresentation> info_list;
info_list.push_back(ImageLoadingTracker::ImageRepresentation(
resource,
ImageLoadingTracker::ImageRepresentation::RESIZE_WHEN_LARGER,
- desired_size_in_dip_.Scale(scale),
+ gfx::Size(resource_size_in_dip_, resource_size_in_dip_).Scale(scale),
scale_factor));
tracker_.LoadImages(extension_, info_list, ImageLoadingTracker::DONT_CACHE);
+
+ // If we have not received |OnImageLoaded|, image load request is
+ // asynchronous.
+ if (load_map_.find(id) != load_map_.end())
+ load_map_[id].is_async = true;
+
+ // If LoadImages returned synchronously and the requested image rep is cached
+ // in the extension, return the cached image rep.
+ if (image_skia_.HasRepresentation(scale_factor))
+ return image_skia_.GetRepresentation(scale_factor);
+
+ return gfx::ImageSkiaRep();
}
-void IconImage::OnImageLoaded(const gfx::Image& image,
+void IconImage::OnImageLoaded(const gfx::Image& image_in,
const std::string& extension_id,
int index) {
LoadMap::iterator load_map_it = load_map_.find(index);
DCHECK(load_map_it != load_map_.end());
- ui::ScaleFactor scale_factor = load_map_it->second;
+ ui::ScaleFactor scale_factor = load_map_it->second.scale_factor;
+ bool is_async = load_map_it->second.is_async;
load_map_.erase(load_map_it);
- if (image.IsEmpty()) {
- // There waas an error loading the image.
- if (observer_)
- observer_->OnIconImageLoadFailed(this, scale_factor);
+ const gfx::ImageSkia* image =
+ image_in.IsEmpty() ? &default_icon_ : image_in.ToImageSkia();
+
+ // If the image resource has been loaded successfully, the returned image
+ // should have the representation for the requested scale factor.
+ DCHECK(image_in.IsEmpty() || image->HasRepresentation(scale_factor));
Jeffrey Yasskin 2012/09/01 01:10:27 Your comment says GetRepresentation should work, n
tbarzic 2012/09/04 21:07:09 Done.
+
+ // Maybe default icon was not set.
+ if (image->isNull())
return;
- }
- DCHECK(image.ToImageSkia()->HasRepresentation(scale_factor));
- gfx::ImageSkiaRep rep = image.ToImageSkia()->GetRepresentation(scale_factor);
+ gfx::ImageSkiaRep rep = image->GetRepresentation(scale_factor);
DCHECK(!rep.is_null());
+
+ // Remove old representation if there is one.
+ image_skia_.RemoveRepresentation(rep.scale_factor());
image_skia_.AddRepresentation(rep);
- if (observer_)
+ // If |tracker_| called us synchronously the image did not really change from
+ // the observers perspective, since the initial image representation is
+ // returned synchronously.
+ if (is_async && observer_)
observer_->OnExtensionIconImageChanged(this);
}

Powered by Google App Engine
This is Rietveld 408576698