summaryrefslogtreecommitdiffstats
path: root/extensions/browser/extension_icon_image.cc
diff options
context:
space:
mode:
authormukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-20 04:53:37 +0000
committermukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-20 04:53:37 +0000
commit326e6f0abee2401bc1676b600653a851283d8b06 (patch)
treebaf666c929ee22517f4c7750369ce4b2bd03f8ae /extensions/browser/extension_icon_image.cc
parent6cb17c0190e848b0af0e618520f5e9429ac0dca3 (diff)
downloadchromium_src-326e6f0abee2401bc1676b600653a851283d8b06.zip
chromium_src-326e6f0abee2401bc1676b600653a851283d8b06.tar.gz
chromium_src-326e6f0abee2401bc1676b600653a851283d8b06.tar.bz2
Moves extension_icon_image and image_loader to extensions/browser
Now extension_icon_image and image_loader are safe to be used outside of Chrome, like AppShell/Athena. BUG=159265, 380421 R=yoz@chromium.org, jamescook@chromium.org TBR=sky@chromium.org, fmalita@chromium.org TEST=unit_tests, compile succeeds Review URL: https://codereview.chromium.org/334053003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278601 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'extensions/browser/extension_icon_image.cc')
-rw-r--r--extensions/browser/extension_icon_image.cc239
1 files changed, 239 insertions, 0 deletions
diff --git a/extensions/browser/extension_icon_image.cc b/extensions/browser/extension_icon_image.cc
new file mode 100644
index 0000000..99473b1
--- /dev/null
+++ b/extensions/browser/extension_icon_image.cc
@@ -0,0 +1,239 @@
+// Copyright 2014 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 "extensions/browser/extension_icon_image.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "content/public/browser/notification_service.h"
+#include "extensions/browser/image_loader.h"
+#include "extensions/common/extension.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_operations.h"
+#include "ui/gfx/image/image_skia_source.h"
+#include "ui/gfx/size.h"
+#include "ui/gfx/size_conversions.h"
+
+// The ImageSkia provided by extensions::IconImage contains ImageSkiaReps that
+// are computed and updated using the following algorithm (if no default icon
+// was supplied, transparent icon is considered the default):
+// - |LoadImageForScaleFactors()| searches the extension for an icon of an
+// appropriate size. If the extension doesn't have a icon resource needed for
+// the image representation, the default icon's representation for the
+// requested scale factor is returned by ImageSkiaSource.
+// - If the extension has the resource, IconImage tries to load it using
+// ImageLoader.
+// - |ImageLoader| is asynchronous.
+// - ImageSkiaSource will initially return transparent image resource of the
+// desired size.
+// - The image will be updated with an appropriate image representation when
+// the |ImageLoader| finishes. The image representation is chosen the same
+// way as in the synchronous case. The observer is notified of the image
+// change, unless the added image representation is transparent (in which
+// case the image had already contained the appropriate image
+// representation).
+
+namespace {
+
+const int kMatchBiggerTreshold = 32;
+
+extensions::ExtensionResource GetExtensionIconResource(
+ const extensions::Extension* extension,
+ const ExtensionIconSet& icons,
+ int size,
+ ExtensionIconSet::MatchType match_type) {
+ std::string path = icons.Get(size, match_type);
+ if (path.empty())
+ return extensions::ExtensionResource();
+
+ return extension->GetResource(path);
+}
+
+class BlankImageSource : public gfx::CanvasImageSource {
+ public:
+ explicit BlankImageSource(const gfx::Size& size_in_dip)
+ : CanvasImageSource(size_in_dip, /*is_opaque =*/ false) {
+ }
+ 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 {
+
+////////////////////////////////////////////////////////////////////////////////
+// IconImage::Source
+
+class IconImage::Source : public gfx::ImageSkiaSource {
+ public:
+ Source(IconImage* host, const gfx::Size& size_in_dip);
+ virtual ~Source();
+
+ void ResetHost();
+
+ private:
+ // gfx::ImageSkiaSource overrides:
+ virtual gfx::ImageSkiaRep GetImageForScale(float scale) OVERRIDE;
+
+ // Used to load images, possibly asynchronously. NULLed out when the IconImage
+ // is destroyed.
+ IconImage* host_;
+
+ // Image whose representations will be used until |host_| loads the real
+ // representations for the image.
+ gfx::ImageSkia blank_image_;
+
+ DISALLOW_COPY_AND_ASSIGN(Source);
+};
+
+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() {
+}
+
+void IconImage::Source::ResetHost() {
+ host_ = NULL;
+}
+
+gfx::ImageSkiaRep IconImage::Source::GetImageForScale(float scale) {
+ gfx::ImageSkiaRep representation;
+ if (host_) {
+ representation =
+ host_->LoadImageForScaleFactor(ui::GetSupportedScaleFactor(scale));
+ }
+
+ if (!representation.is_null())
+ return representation;
+
+ return blank_image_.GetRepresentation(scale);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// IconImage
+
+IconImage::IconImage(
+ content::BrowserContext* context,
+ const Extension* extension,
+ const ExtensionIconSet& icon_set,
+ int resource_size_in_dip,
+ const gfx::ImageSkia& default_icon,
+ Observer* observer)
+ : browser_context_(context),
+ extension_(extension),
+ icon_set_(icon_set),
+ resource_size_in_dip_(resource_size_in_dip),
+ observer_(observer),
+ source_(NULL),
+ default_icon_(gfx::ImageSkiaOperations::CreateResizedImage(
+ default_icon,
+ skia::ImageOperations::RESIZE_BEST,
+ gfx::Size(resource_size_in_dip, resource_size_in_dip))),
+ weak_ptr_factory_(this) {
+ 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_REMOVED,
+ content::NotificationService::AllSources());
+}
+
+IconImage::~IconImage() {
+ source_->ResetHost();
+}
+
+gfx::ImageSkiaRep IconImage::LoadImageForScaleFactor(
+ ui::ScaleFactor scale_factor) {
+ // Do nothing if extension is unloaded.
+ if (!extension_)
+ return gfx::ImageSkiaRep();
+
+ const float scale = ui::GetScaleForScaleFactor(scale_factor);
+ const int resource_size_in_pixel =
+ static_cast<int>(resource_size_in_dip_ * scale);
+
+ extensions::ExtensionResource resource;
+
+ // Find extension resource for non bundled component extensions.
+ // We try loading bigger image only if resource size is >= 32.
+ if (resource_size_in_pixel >= kMatchBiggerTreshold) {
+ resource = GetExtensionIconResource(extension_, icon_set_,
+ resource_size_in_pixel, ExtensionIconSet::MATCH_BIGGER);
+ }
+
+ // If resource is not found by now, try matching smaller one.
+ if (resource.empty()) {
+ resource = GetExtensionIconResource(extension_, icon_set_,
+ resource_size_in_pixel, ExtensionIconSet::MATCH_SMALLER);
+ }
+
+ // If there is no resource found, return default icon.
+ if (resource.empty())
+ return default_icon_.GetRepresentation(scale);
+
+ std::vector<ImageLoader::ImageRepresentation> info_list;
+ info_list.push_back(ImageLoader::ImageRepresentation(
+ resource,
+ ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
+ gfx::ToFlooredSize(gfx::ScaleSize(
+ gfx::Size(resource_size_in_dip_, resource_size_in_dip_), scale)),
+ scale_factor));
+
+ extensions::ImageLoader* loader =
+ extensions::ImageLoader::Get(browser_context_);
+ loader->LoadImagesAsync(extension_, info_list,
+ base::Bind(&IconImage::OnImageLoaded,
+ weak_ptr_factory_.GetWeakPtr(),
+ scale));
+
+ return gfx::ImageSkiaRep();
+}
+
+void IconImage::OnImageLoaded(float scale, const gfx::Image& image_in) {
+ const gfx::ImageSkia* image =
+ image_in.IsEmpty() ? &default_icon_ : image_in.ToImageSkia();
+
+ // Maybe default icon was not set.
+ if (image->isNull())
+ return;
+
+ gfx::ImageSkiaRep rep = image->GetRepresentation(scale);
+ DCHECK(!rep.is_null());
+ DCHECK_EQ(scale, rep.scale());
+
+ // Remove old representation if there is one.
+ image_skia_.RemoveRepresentation(scale);
+ image_skia_.AddRepresentation(rep);
+
+ if (observer_)
+ observer_->OnExtensionIconImageChanged(this);
+}
+
+void IconImage::Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ DCHECK_EQ(type, chrome::NOTIFICATION_EXTENSION_REMOVED);
+
+ const Extension* extension = content::Details<const Extension>(details).ptr();
+
+ if (extension_ == extension)
+ extension_ = NULL;
+}
+
+} // namespace extensions