// 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_ #pragma once #include #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" #include "chrome/common/extensions/extension_resource.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "ui/gfx/size.h" class Extension; class SkBitmap; 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 // SkBitmap 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 single image to load from a extension resource. struct ImageInfo { ImageInfo(const ExtensionResource& resource, gfx::Size max_size); ~ImageInfo(); ExtensionResource resource; // If the loaded image is larger than |max_size| it will be resized to those // dimensions. gfx::Size max_size; }; 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. void LoadImage(const 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 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 image load operation for one or more images. struct PendingLoadInfo { PendingLoadInfo(); ~PendingLoadInfo(); const Extension* extension; // This is cached separate from |extension| in case the extension in // unloaded. std::string extension_id; CacheParam cache; size_t pending_count; std::vector bitmaps; }; // Maps an integer identifying a load request to a PendingLoadInfo. typedef std::map LoadMap; class ImageLoader; // When an image has finished loaded and been resized on the file thread, it // is posted back to this method on the original thread. This method then // calls the observer's OnImageLoaded and deletes the ImageLoadingTracker if // it was the last image in the list. The |original_size| should be the size // of the image before any resizing was done. // |image| may be null if the file failed to decode. void OnImageLoaded(SkBitmap* image, const ExtensionResource& resource, 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 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_