Make default apps cache multiprofile friendly
[chromium-blink-merge.git] / chrome / browser / extensions / extension_icon_image.cc
blobfbd1ee4526dba624360c4d90c3ecfee25a903ee4
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/extension_icon_image.h"
7 #include <vector>
9 #include "base/bind.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/extensions/image_loader.h"
12 #include "chrome/common/extensions/extension.h"
13 #include "content/public/browser/notification_service.h"
14 #include "ui/gfx/canvas.h"
15 #include "ui/gfx/image/canvas_image_source.h"
16 #include "ui/gfx/image/image.h"
17 #include "ui/gfx/image/image_skia_operations.h"
18 #include "ui/gfx/image/image_skia_source.h"
19 #include "ui/gfx/size.h"
20 #include "ui/gfx/size_conversions.h"
22 // The ImageSkia provided by extensions::IconImage contains ImageSkiaReps that
23 // are computed and updated using the following algorithm (if no default icon
24 // was supplied, transparent icon is considered the default):
25 // - |LoadImageForScaleFactors()| searches the extension for an icon of an
26 // appropriate size. If the extension doesn't have a icon resource needed for
27 // the image representation, the default icon's representation for the
28 // requested scale factor is returned by ImageSkiaSource.
29 // - If the extension has the resource, IconImage tries to load it using
30 // ImageLoader.
31 // - |ImageLoader| is asynchronous.
32 // - ImageSkiaSource will initially return transparent image resource of the
33 // desired size.
34 // - The image will be updated with an appropriate image representation when
35 // the |ImageLoader| finishes. The image representation is chosen the same
36 // way as in the synchronous case. The observer is notified of the image
37 // change, unless the added image representation is transparent (in which
38 // case the image had already contained the appropriate image
39 // representation).
41 namespace {
43 const int kMatchBiggerTreshold = 32;
45 extensions::ExtensionResource GetExtensionIconResource(
46 const extensions::Extension* extension,
47 const ExtensionIconSet& icons,
48 int size,
49 ExtensionIconSet::MatchType match_type) {
50 std::string path = icons.Get(size, match_type);
51 if (path.empty())
52 return extensions::ExtensionResource();
54 return extension->GetResource(path);
57 class BlankImageSource : public gfx::CanvasImageSource {
58 public:
59 explicit BlankImageSource(const gfx::Size& size_in_dip)
60 : CanvasImageSource(size_in_dip, /*is_opaque =*/ false) {
62 virtual ~BlankImageSource() {}
64 private:
65 // gfx::CanvasImageSource overrides:
66 virtual void Draw(gfx::Canvas* canvas) OVERRIDE {
67 canvas->DrawColor(SkColorSetARGB(0, 0, 0, 0));
70 DISALLOW_COPY_AND_ASSIGN(BlankImageSource);
73 } // namespace
75 namespace extensions {
77 ////////////////////////////////////////////////////////////////////////////////
78 // IconImage::Source
80 class IconImage::Source : public gfx::ImageSkiaSource {
81 public:
82 Source(IconImage* host, const gfx::Size& size_in_dip);
83 virtual ~Source();
85 void ResetHost();
87 private:
88 // gfx::ImageSkiaSource overrides:
89 virtual gfx::ImageSkiaRep GetImageForScale(
90 ui::ScaleFactor scale_factor) OVERRIDE;
92 // Used to load images, possibly asynchronously. NULLed out when the IconImage
93 // is destroyed.
94 IconImage* host_;
96 // Image whose representations will be used until |host_| loads the real
97 // representations for the image.
98 gfx::ImageSkia blank_image_;
100 DISALLOW_COPY_AND_ASSIGN(Source);
103 IconImage::Source::Source(IconImage* host, const gfx::Size& size_in_dip)
104 : host_(host),
105 blank_image_(new BlankImageSource(size_in_dip), size_in_dip) {
108 IconImage::Source::~Source() {
111 void IconImage::Source::ResetHost() {
112 host_ = NULL;
115 gfx::ImageSkiaRep IconImage::Source::GetImageForScale(
116 ui::ScaleFactor scale_factor) {
117 gfx::ImageSkiaRep representation;
118 if (host_)
119 representation = host_->LoadImageForScaleFactor(scale_factor);
121 if (!representation.is_null())
122 return representation;
124 return blank_image_.GetRepresentation(scale_factor);
127 ////////////////////////////////////////////////////////////////////////////////
128 // IconImage
130 IconImage::IconImage(
131 Profile* profile,
132 const Extension* extension,
133 const ExtensionIconSet& icon_set,
134 int resource_size_in_dip,
135 const gfx::ImageSkia& default_icon,
136 Observer* observer)
137 : profile_(profile),
138 extension_(extension),
139 icon_set_(icon_set),
140 resource_size_in_dip_(resource_size_in_dip),
141 observer_(observer),
142 source_(NULL),
143 default_icon_(gfx::ImageSkiaOperations::CreateResizedImage(
144 default_icon,
145 skia::ImageOperations::RESIZE_BEST,
146 gfx::Size(resource_size_in_dip, resource_size_in_dip))),
147 weak_ptr_factory_(this) {
148 gfx::Size resource_size(resource_size_in_dip, resource_size_in_dip);
149 source_ = new Source(this, resource_size);
150 image_skia_ = gfx::ImageSkia(source_, resource_size);
152 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
153 content::NotificationService::AllSources());
156 IconImage::~IconImage() {
157 source_->ResetHost();
160 gfx::ImageSkiaRep IconImage::LoadImageForScaleFactor(
161 ui::ScaleFactor scale_factor) {
162 // Do nothing if extension is unloaded.
163 if (!extension_)
164 return gfx::ImageSkiaRep();
166 const float scale = ui::GetScaleFactorScale(scale_factor);
167 const int resource_size_in_pixel =
168 static_cast<int>(resource_size_in_dip_ * scale);
170 extensions::ExtensionResource resource;
172 // Find extension resource for non bundled component extensions.
173 // We try loading bigger image only if resource size is >= 32.
174 if (resource_size_in_pixel >= kMatchBiggerTreshold) {
175 resource = GetExtensionIconResource(extension_, icon_set_,
176 resource_size_in_pixel, ExtensionIconSet::MATCH_BIGGER);
179 // If resource is not found by now, try matching smaller one.
180 if (resource.empty()) {
181 resource = GetExtensionIconResource(extension_, icon_set_,
182 resource_size_in_pixel, ExtensionIconSet::MATCH_SMALLER);
185 // If there is no resource found, return default icon.
186 if (resource.empty())
187 return default_icon_.GetRepresentation(scale_factor);
189 std::vector<ImageLoader::ImageRepresentation> info_list;
190 info_list.push_back(ImageLoader::ImageRepresentation(
191 resource,
192 ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
193 gfx::ToFlooredSize(gfx::ScaleSize(
194 gfx::Size(resource_size_in_dip_, resource_size_in_dip_), scale)),
195 scale_factor));
197 extensions::ImageLoader* loader = extensions::ImageLoader::Get(profile_);
198 loader->LoadImagesAsync(extension_, info_list,
199 base::Bind(&IconImage::OnImageLoaded,
200 weak_ptr_factory_.GetWeakPtr(),
201 scale_factor));
203 return gfx::ImageSkiaRep();
206 void IconImage::OnImageLoaded(ui::ScaleFactor scale_factor,
207 const gfx::Image& image_in) {
208 const gfx::ImageSkia* image =
209 image_in.IsEmpty() ? &default_icon_ : image_in.ToImageSkia();
211 // Maybe default icon was not set.
212 if (image->isNull())
213 return;
215 gfx::ImageSkiaRep rep = image->GetRepresentation(scale_factor);
216 DCHECK(!rep.is_null());
217 DCHECK_EQ(scale_factor, rep.scale_factor());
219 // Remove old representation if there is one.
220 image_skia_.RemoveRepresentation(rep.scale_factor());
221 image_skia_.AddRepresentation(rep);
223 if (observer_)
224 observer_->OnExtensionIconImageChanged(this);
227 void IconImage::Observe(int type,
228 const content::NotificationSource& source,
229 const content::NotificationDetails& details) {
230 DCHECK_EQ(type, chrome::NOTIFICATION_EXTENSION_UNLOADED);
232 const Extension* extension =
233 content::Details<extensions::UnloadedExtensionInfo>(details)->extension;
235 if (extension_ == extension)
236 extension_ = NULL;
239 } // namespace extensions