blob: be631e7a647acdaa0c91b90f0e81c2aa8e2dfbff [file] [log] [blame] [edit]
// 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_