// 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 #include #include #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& 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 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 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_