// 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_THEMES_BROWSER_THEME_PACK_H_ #define CHROME_BROWSER_THEMES_BROWSER_THEME_PACK_H_ #include <map> #include <string> #include <vector> #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" #include "base/sequenced_task_runner_helpers.h" #include "chrome/browser/themes/custom_theme_supplier.h" #include "extensions/common/extension.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/base/layout.h" #include "ui/gfx/color_utils.h" namespace base { class DictionaryValue; class FilePath; class RefCountedMemory; } namespace extensions { class Extensions; } namespace gfx { class Image; } namespace ui { class DataPack; } // An optimized representation of a theme, backed by a mmapped DataPack. // // The idea is to pre-process all images (tinting, compositing, etc) at theme // install time, save all the PNG-ified data into an mmappable file so we don't // suffer multiple file system access times, therefore solving two of the // problems with the previous implementation. // // A note on const-ness. All public, non-static methods are const. We do this // because once we've constructed a BrowserThemePack through the // BuildFromExtension() interface, we WriteToDisk() on a thread other than the // UI thread that consumes a BrowserThemePack. There is no locking; thread // safety between the writing thread and the UI thread is ensured by having the // data be immutable. // // BrowserThemePacks are always deleted on the file thread because in the // common case, they are backed by mmapped data and the unmmapping operation // will trip our IO on the UI thread detector. class BrowserThemePack : public CustomThemeSupplier { public: // Builds the theme pack from all data from |extension|. This is often done // on a separate thread as it takes so long. This can fail and return NULL in // the case where the theme has invalid data. static scoped_refptr<BrowserThemePack> BuildFromExtension( const extensions::Extension* extension); // Builds the theme pack from a previously performed WriteToDisk(). This // operation should be relatively fast, as it should be an mmap() and some // pointer swizzling. Returns NULL on any error attempting to read |path|. static scoped_refptr<BrowserThemePack> BuildFromDataPack( const base::FilePath& path, const std::string& expected_id); // Returns the set of image IDRs which can be overwritten by a user provided // theme. static void GetThemeableImageIDRs(std::set<int>* result); // Builds a data pack on disk at |path| for future quick loading by // BuildFromDataPack(). Often (but not always) called from the file thread; // implementation should be threadsafe because neither thread will write to // |image_memory_| and the worker thread will keep a reference to prevent // destruction. bool WriteToDisk(const base::FilePath& path) const; // Overridden from CustomThemeSupplier: virtual bool GetTint(int id, color_utils::HSL* hsl) const OVERRIDE; virtual bool GetColor(int id, SkColor* color) const OVERRIDE; virtual bool GetDisplayProperty(int id, int* result) const OVERRIDE; virtual gfx::Image GetImageNamed(int id) OVERRIDE; virtual base::RefCountedMemory* GetRawData( int id, ui::ScaleFactor scale_factor) const OVERRIDE; virtual bool HasCustomImage(int id) const OVERRIDE; private: friend class BrowserThemePackTest; // Cached images. typedef std::map<int, gfx::Image> ImageCache; // The raw PNG memory associated with a certain id. typedef std::map<int, scoped_refptr<base::RefCountedMemory> > RawImages; // The type passed to ui::DataPack::WritePack. typedef std::map<uint16, base::StringPiece> RawDataForWriting; // Maps scale factors (enum values) to file paths. typedef std::map<ui::ScaleFactor, base::FilePath> ScaleFactorToFileMap; // Maps image ids to maps of scale factors to file paths. typedef std::map<int, ScaleFactorToFileMap> FilePathMap; // Default. Everything is empty. BrowserThemePack(); virtual ~BrowserThemePack(); // Builds a header ready to write to disk. void BuildHeader(const extensions::Extension* extension); // Transforms the JSON tint values into their final versions in the |tints_| // array. void BuildTintsFromJSON(const base::DictionaryValue* tints_value); // Transforms the JSON color values into their final versions in the // |colors_| array and also fills in unspecified colors based on tint values. void BuildColorsFromJSON(const base::DictionaryValue* color_value); // Implementation details of BuildColorsFromJSON(). void ReadColorsFromJSON(const base::DictionaryValue* colors_value, std::map<int, SkColor>* temp_colors); void GenerateMissingColors(std::map<int, SkColor>* temp_colors); // Transforms the JSON display properties into |display_properties_|. void BuildDisplayPropertiesFromJSON( const base::DictionaryValue* display_value); // Parses the image names out of an extension. void ParseImageNamesFromJSON(const base::DictionaryValue* images_value, const base::FilePath& images_path, FilePathMap* file_paths) const; // Helper function to populate the FilePathMap. void AddFileAtScaleToMap(const std::string& image_name, ui::ScaleFactor scale_factor, const base::FilePath& image_path, FilePathMap* file_paths) const; // Creates the data for |source_images_| from |file_paths|. void BuildSourceImagesArray(const FilePathMap& file_paths); // Loads the unmodified images packed in the extension to SkBitmaps. Returns // true if all images loaded. bool LoadRawBitmapsTo(const FilePathMap& file_paths, ImageCache* image_cache); // Populate |images| cache with empty gfx::Images. Image reps are lazily // generated when an image rep is requested via ImageSkia::GetRepresentation. // Source and destination is |images|. void CreateImages(ImageCache* images) const; // Crops images down to a size such that most of the cropped image will be // displayed in the UI. Cropping is useful because images from custom themes // can be of any size. Source and destination is |images|. void CropImages(ImageCache* images) const; // Creates tinted and composited frame images. Source and destination is // |images|. void CreateFrameImages(ImageCache* images) const; // Creates button images tinted with |button_tint| and places them in // processed_images. void CreateTintedButtons(const color_utils::HSL& button_tint, ImageCache* processed_images) const; // Creates the semi-transparent tab background images, putting the results // in |images|. Must be called after GenerateFrameImages(). void CreateTabBackgroundImages(ImageCache* images) const; // Takes all the SkBitmaps in |images|, encodes them as PNGs and places // them in |reencoded_images|. void RepackImages(const ImageCache& images, RawImages* reencoded_images) const; // Takes all images in |source| and puts them in |destination|, freeing any // image already in |destination| that |source| would overwrite. void MergeImageCaches(const ImageCache& source, ImageCache* destination) const; // Copies images from |source| to |destination| such that the lifetimes of // the images in |destination| are not affected by the lifetimes of the // images in |source|. void CopyImagesTo(const ImageCache& source, ImageCache* destination) const; // Changes the RefCountedMemory based |images| into StringPiece data in |out|. void AddRawImagesTo(const RawImages& images, RawDataForWriting* out) const; // Retrieves the tint OR the default tint. Unlike the public interface, we // always need to return a reasonable tint here, instead of partially // querying if the tint exists. color_utils::HSL GetTintInternal(int id) const; // Returns a unique id to use to store the raw bitmap for |prs_id| at // |scale_factor| in memory. int GetRawIDByPersistentID(int prs_id, ui::ScaleFactor scale_factor) const; // Returns true if the |key| specifies a valid scale (e.g. "100") and // the corresponding scale factor is currently in use. If true, returns // the scale factor in |scale_factor|. bool GetScaleFactorFromManifestKey(const std::string& key, ui::ScaleFactor* scale_factor) const; // Generates raw images for any missing scale from an available scale. void GenerateRawImageForAllSupportedScales(int prs_id); // Data pack, if we have one. scoped_ptr<ui::DataPack> data_pack_; // All structs written to disk need to be packed; no alignment tricks here, // please. #pragma pack(push,1) // Header that is written to disk. struct BrowserThemePackHeader { // Numeric version to make sure we're compatible in the future. int32 version; // 1 if little_endian. 0 if big_endian. On mismatch, abort load. int32 little_endian; // theme_id without NULL terminator. uint8 theme_id[16]; } *header_; // The remaining structs represent individual entries in an array. For the // following three structs, BrowserThemePack will either allocate an array or // will point directly to mmapped data. struct TintEntry { int32 id; double h; double s; double l; } *tints_; struct ColorPair { int32 id; SkColor color; } *colors_; struct DisplayPropertyPair { int32 id; int32 property; } *display_properties_; // A list of included source images. A pointer to a -1 terminated array of // our persistent IDs. int* source_images_; #pragma pack(pop) // The scale factors represented by the images in the theme pack. std::vector<ui::ScaleFactor> scale_factors_; // References to raw PNG data. This map isn't touched when |data_pack_| is // non-NULL; |image_memory_| is only filled during BuildFromExtension(). Any // image data that needs to be written to the DataPack during WriteToDisk() // needs to be in |image_memory_|. RawImages image_memory_; // Loaded images. These are loaded from |image_memory_|, from |data_pack_|, // and by BuildFromExtension(). These images should only be accessed on the UI // thread. ImageCache images_on_ui_thread_; // Cache of images created in BuildFromExtension(). Once the theme pack is // created, this cache should only be accessed on the file thread. There // should be no IDs in |image_memory_| that are in |images_on_file_thread_| // or vice versa. ImageCache images_on_file_thread_; DISALLOW_COPY_AND_ASSIGN(BrowserThemePack); }; #endif // CHROME_BROWSER_THEMES_BROWSER_THEME_PACK_H_