diff options
author | mukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-20 04:53:37 +0000 |
---|---|---|
committer | mukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-20 04:53:37 +0000 |
commit | 326e6f0abee2401bc1676b600653a851283d8b06 (patch) | |
tree | baf666c929ee22517f4c7750369ce4b2bd03f8ae /extensions/browser/extension_icon_image.cc | |
parent | 6cb17c0190e848b0af0e618520f5e9429ac0dca3 (diff) | |
download | chromium_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.cc | 239 |
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 |