summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions/image_loading_tracker.h
blob: be631e7a647acdaa0c91b90f0e81c2aa8e2dfbff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// Copyright (c) 2012 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.

#ifndef CHROME_BROWSER_EXTENSIONS_IMAGE_LOADING_TRACKER_H_
#define CHROME_BROWSER_EXTENSIONS_IMAGE_LOADING_TRACKER_H_

#include <map>
#include <string>
#include <vector>

#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/extension_resource.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "ui/base/layout.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/size.h"

class SkBitmap;

namespace extensions {
class Extension;
}

namespace gfx {
class Image;
}

// The views need to load their icons asynchronously but might be deleted before
// the images have loaded. This class encapsulates a loader class that stays
// alive while the request is in progress (manages its own lifetime) and keeps
// track of whether the view still cares about the icon loading.
//
// To use this class, have your class derive from ImageLoadingTracker::Observer,
// and add a member variable ImageLoadingTracker tracker_. Then override
// Observer::OnImageLoaded and call:
//   tracker_.LoadImage(extension, resource, max_size, false);
// ... and wait for OnImageLoaded to be called back on you with a pointer to the
// ImageSkia loaded.
// NOTE: if the image is available already (or the resource is not valid), the
// Observer is notified immediately from the call to LoadImage. In other words,
// by the time LoadImage returns the observer has been notified.
//
class ImageLoadingTracker : public content::NotificationObserver {
 public:
  enum CacheParam {
    CACHE,
    DONT_CACHE
  };

  class Observer {
   public:
    // Will be called when the image with the given index has loaded.
    // |image| can be empty if a valid image was not found or it failed to
    // decode. |extension_id| is the ID of the extension the images are loaded
    // from.  |index| represents the index of the image just loaded (starts at 0
    // and increments every time LoadImage is called).
    virtual void OnImageLoaded(const gfx::Image& image,
                               const std::string& extension_id,
                               int index) = 0;

   protected:
    virtual ~Observer();
  };

  // Information about a singe image representation to load from an extension
  // resource.
  struct ImageRepresentation {
    // Enum values to indicate whether to resize loaded bitmap when it is larger
    // than |desired_size| or always resize it.
    enum ResizeCondition {
      RESIZE_WHEN_LARGER,
      ALWAYS_RESIZE,
    };

    ImageRepresentation(const ExtensionResource& resource,
                        ResizeCondition resize_method,
                        const gfx::Size& desired_size,
                        ui::ScaleFactor scale_factor);
    ~ImageRepresentation();

    // Extension resource to load.
    ExtensionResource resource;

    ResizeCondition resize_method;

    // When |resize_method| is ALWAYS_RESIZE or when the loaded image is larger
    // than |desired_size| it will be resized to these dimensions.
    gfx::Size desired_size;

    // |scale_factor| is used to construct the loaded gfx::ImageSkia.
    ui::ScaleFactor scale_factor;
  };

  // Returns true if given extension id is a special component extension that
  // has its resource bundled.
  // TODO(xiyuan): Move this out of this class.
  static bool IsSpecialBundledExtensionId(const std::string& extension_id);

  explicit ImageLoadingTracker(Observer* observer);
  virtual ~ImageLoadingTracker();

  // Specify image resource to load. If the loaded image is larger than
  // |max_size| it will be resized to those dimensions. IMPORTANT NOTE: this
  // function may call back your observer synchronously (ie before it returns)
  // if the image was found in the cache.
  // Note this method loads a raw bitmap from the resource. All sizes given are
  // assumed to be in pixels.
  void LoadImage(const extensions::Extension* extension,
                 const ExtensionResource& resource,
                 const gfx::Size& max_size,
                 CacheParam cache);

  // Same as LoadImage() above except it loads multiple images from the same
  // extension. This is used to load multiple resolutions of the same image
  // type.
  void LoadImages(const extensions::Extension* extension,
                  const std::vector<ImageRepresentation>& info_list,
                  CacheParam cache);

  // Returns the ID used for the next image that is loaded. That is, the return
  // value from this method corresponds to the int that is passed to
  // OnImageLoaded() the next time LoadImage() is invoked.
  int next_id() const { return next_id_; }

 private:
  // Information for pending resource load operation for one or more image
  // representations.
  struct PendingLoadInfo {
    PendingLoadInfo();
    ~PendingLoadInfo();

    const extensions::Extension* extension;
    // This is cached separate from |extension| in case the extension is
    // unloaded.
    std::string extension_id;
    CacheParam cache;
    size_t pending_count;
    gfx::ImageSkia image_skia;
  };

  // Maps an integer identifying a load request to a PendingLoadInfo.
  typedef std::map<int, PendingLoadInfo> LoadMap;

  class ImageLoader;

  // Called on the calling thread when the bitmap finishes loading.
  // |bitmap| may be null if the image file failed to decode.
  void OnBitmapLoaded(const SkBitmap* bitmap,
                      const ImageRepresentation& image_info,
                      const gfx::Size& original_size,
                      int id,
                      bool should_cache);

  // Checks whether image is a component extension resource. Returns false
  // if a given |resource| does not have a corresponding image in bundled
  // resources. Otherwise fills |resource_id|.
  bool IsComponentExtensionResource(const extensions::Extension* extension,
                                    const ExtensionResource& resource,
                                    int& resource_id) const;

  // content::NotificationObserver method. If an extension is uninstalled while
  // we're waiting for the image we remove the entry from load_map_.
  virtual void Observe(int type,
                       const content::NotificationSource& source,
                       const content::NotificationDetails& details) OVERRIDE;

  // The view that is waiting for the image to load.
  Observer* observer_;

  // ID to use for next image requested. This is an ever increasing integer.
  int next_id_;

  // The object responsible for loading the image on the File thread.
  scoped_refptr<ImageLoader> loader_;

  // Information for each LoadImage request is cached here. The integer
  // identifies the id assigned to the request.
  LoadMap load_map_;

  content::NotificationRegistrar registrar_;

  FRIEND_TEST_ALL_PREFIXES(ImageLoadingTrackerTest,
                           IsComponentExtensionResource);

  DISALLOW_COPY_AND_ASSIGN(ImageLoadingTracker);
};

#endif  // CHROME_BROWSER_EXTENSIONS_IMAGE_LOADING_TRACKER_H_