Home | History | Annotate | Download | only in themes
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef CHROME_BROWSER_THEMES_BROWSER_THEME_PACK_H_
      6 #define CHROME_BROWSER_THEMES_BROWSER_THEME_PACK_H_
      7 
      8 #include <map>
      9 #include <string>
     10 #include <vector>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "base/sequenced_task_runner_helpers.h"
     15 #include "chrome/browser/themes/custom_theme_supplier.h"
     16 #include "extensions/common/extension.h"
     17 #include "third_party/skia/include/core/SkColor.h"
     18 #include "ui/base/layout.h"
     19 #include "ui/gfx/color_utils.h"
     20 
     21 namespace base {
     22 class DictionaryValue;
     23 class FilePath;
     24 class RefCountedMemory;
     25 }
     26 
     27 namespace extensions {
     28 class Extensions;
     29 }
     30 
     31 namespace gfx {
     32 class Image;
     33 }
     34 
     35 namespace ui {
     36 class DataPack;
     37 }
     38 
     39 // An optimized representation of a theme, backed by a mmapped DataPack.
     40 //
     41 // The idea is to pre-process all images (tinting, compositing, etc) at theme
     42 // install time, save all the PNG-ified data into an mmappable file so we don't
     43 // suffer multiple file system access times, therefore solving two of the
     44 // problems with the previous implementation.
     45 //
     46 // A note on const-ness. All public, non-static methods are const.  We do this
     47 // because once we've constructed a BrowserThemePack through the
     48 // BuildFromExtension() interface, we WriteToDisk() on a thread other than the
     49 // UI thread that consumes a BrowserThemePack. There is no locking; thread
     50 // safety between the writing thread and the UI thread is ensured by having the
     51 // data be immutable.
     52 //
     53 // BrowserThemePacks are always deleted on the file thread because in the
     54 // common case, they are backed by mmapped data and the unmmapping operation
     55 // will trip our IO on the UI thread detector.
     56 class BrowserThemePack : public CustomThemeSupplier {
     57  public:
     58   // Builds the theme pack from all data from |extension|. This is often done
     59   // on a separate thread as it takes so long. This can fail and return NULL in
     60   // the case where the theme has invalid data.
     61   static scoped_refptr<BrowserThemePack> BuildFromExtension(
     62       const extensions::Extension* extension);
     63 
     64   // Builds the theme pack from a previously performed WriteToDisk(). This
     65   // operation should be relatively fast, as it should be an mmap() and some
     66   // pointer swizzling. Returns NULL on any error attempting to read |path|.
     67   static scoped_refptr<BrowserThemePack> BuildFromDataPack(
     68       const base::FilePath& path, const std::string& expected_id);
     69 
     70   // Returns the set of image IDRs which can be overwritten by a user provided
     71   // theme.
     72   static void GetThemeableImageIDRs(std::set<int>* result);
     73 
     74   // Builds a data pack on disk at |path| for future quick loading by
     75   // BuildFromDataPack(). Often (but not always) called from the file thread;
     76   // implementation should be threadsafe because neither thread will write to
     77   // |image_memory_| and the worker thread will keep a reference to prevent
     78   // destruction.
     79   bool WriteToDisk(const base::FilePath& path) const;
     80 
     81   // Overridden from CustomThemeSupplier:
     82   virtual bool GetTint(int id, color_utils::HSL* hsl) const OVERRIDE;
     83   virtual bool GetColor(int id, SkColor* color) const OVERRIDE;
     84   virtual bool GetDisplayProperty(int id, int* result) const OVERRIDE;
     85   virtual gfx::Image GetImageNamed(int id) OVERRIDE;
     86   virtual base::RefCountedMemory* GetRawData(
     87       int id, ui::ScaleFactor scale_factor) const OVERRIDE;
     88   virtual bool HasCustomImage(int id) const OVERRIDE;
     89 
     90  private:
     91   friend class BrowserThemePackTest;
     92 
     93   // Cached images.
     94   typedef std::map<int, gfx::Image> ImageCache;
     95 
     96   // The raw PNG memory associated with a certain id.
     97   typedef std::map<int, scoped_refptr<base::RefCountedMemory> > RawImages;
     98 
     99   // The type passed to ui::DataPack::WritePack.
    100   typedef std::map<uint16, base::StringPiece> RawDataForWriting;
    101 
    102   // Maps scale factors (enum values) to file paths.
    103   typedef std::map<ui::ScaleFactor, base::FilePath> ScaleFactorToFileMap;
    104 
    105   // Maps image ids to maps of scale factors to file paths.
    106   typedef std::map<int, ScaleFactorToFileMap> FilePathMap;
    107 
    108   // Default. Everything is empty.
    109   BrowserThemePack();
    110 
    111   virtual ~BrowserThemePack();
    112 
    113   // Builds a header ready to write to disk.
    114   void BuildHeader(const extensions::Extension* extension);
    115 
    116   // Transforms the JSON tint values into their final versions in the |tints_|
    117   // array.
    118   void BuildTintsFromJSON(const base::DictionaryValue* tints_value);
    119 
    120   // Transforms the JSON color values into their final versions in the
    121   // |colors_| array and also fills in unspecified colors based on tint values.
    122   void BuildColorsFromJSON(const base::DictionaryValue* color_value);
    123 
    124   // Implementation details of BuildColorsFromJSON().
    125   void ReadColorsFromJSON(const base::DictionaryValue* colors_value,
    126                           std::map<int, SkColor>* temp_colors);
    127   void GenerateMissingColors(std::map<int, SkColor>* temp_colors);
    128 
    129   // Transforms the JSON display properties into |display_properties_|.
    130   void BuildDisplayPropertiesFromJSON(
    131       const base::DictionaryValue* display_value);
    132 
    133   // Parses the image names out of an extension.
    134   void ParseImageNamesFromJSON(const base::DictionaryValue* images_value,
    135                                const base::FilePath& images_path,
    136                                FilePathMap* file_paths) const;
    137 
    138   // Helper function to populate the FilePathMap.
    139   void AddFileAtScaleToMap(const std::string& image_name,
    140                            ui::ScaleFactor scale_factor,
    141                            const base::FilePath& image_path,
    142                            FilePathMap* file_paths) const;
    143 
    144   // Creates the data for |source_images_| from |file_paths|.
    145   void BuildSourceImagesArray(const FilePathMap& file_paths);
    146 
    147   // Loads the unmodified images packed in the extension to SkBitmaps. Returns
    148   // true if all images loaded.
    149   bool LoadRawBitmapsTo(const FilePathMap& file_paths,
    150                         ImageCache* image_cache);
    151 
    152   // Populate |images| cache with empty gfx::Images. Image reps are lazily
    153   // generated when an image rep is requested via ImageSkia::GetRepresentation.
    154   // Source and destination is |images|.
    155   void CreateImages(ImageCache* images) const;
    156 
    157   // Crops images down to a size such that most of the cropped image will be
    158   // displayed in the UI. Cropping is useful because images from custom themes
    159   // can be of any size. Source and destination is |images|.
    160   void CropImages(ImageCache* images) const;
    161 
    162   // Creates tinted and composited frame images. Source and destination is
    163   // |images|.
    164   void CreateFrameImages(ImageCache* images) const;
    165 
    166   // Creates button images tinted with |button_tint| and places them in
    167   // processed_images.
    168   void CreateTintedButtons(const color_utils::HSL& button_tint,
    169                            ImageCache* processed_images) const;
    170 
    171   // Creates the semi-transparent tab background images, putting the results
    172   // in |images|. Must be called after GenerateFrameImages().
    173   void CreateTabBackgroundImages(ImageCache* images) const;
    174 
    175   // Takes all the SkBitmaps in |images|, encodes them as PNGs and places
    176   // them in |reencoded_images|.
    177   void RepackImages(const ImageCache& images,
    178                     RawImages* reencoded_images) const;
    179 
    180   // Takes all images in |source| and puts them in |destination|, freeing any
    181   // image already in |destination| that |source| would overwrite.
    182   void MergeImageCaches(const ImageCache& source,
    183                         ImageCache* destination) const;
    184 
    185   // Copies images from |source| to |destination| such that the lifetimes of
    186   // the images in |destination| are not affected by the lifetimes of the
    187   // images in |source|.
    188   void CopyImagesTo(const ImageCache& source, ImageCache* destination) const;
    189 
    190   // Changes the RefCountedMemory based |images| into StringPiece data in |out|.
    191   void AddRawImagesTo(const RawImages& images, RawDataForWriting* out) const;
    192 
    193   // Retrieves the tint OR the default tint. Unlike the public interface, we
    194   // always need to return a reasonable tint here, instead of partially
    195   // querying if the tint exists.
    196   color_utils::HSL GetTintInternal(int id) const;
    197 
    198   // Returns a unique id to use to store the raw bitmap for |prs_id| at
    199   // |scale_factor| in memory.
    200   int GetRawIDByPersistentID(int prs_id, ui::ScaleFactor scale_factor) const;
    201 
    202   // Returns true if the |key| specifies a valid scale (e.g. "100") and
    203   // the corresponding scale factor is currently in use. If true, returns
    204   // the scale factor in |scale_factor|.
    205   bool GetScaleFactorFromManifestKey(const std::string& key,
    206                                      ui::ScaleFactor* scale_factor) const;
    207 
    208   // Generates raw images for any missing scale from an available scale.
    209   void GenerateRawImageForAllSupportedScales(int prs_id);
    210 
    211   // Data pack, if we have one.
    212   scoped_ptr<ui::DataPack> data_pack_;
    213 
    214   // All structs written to disk need to be packed; no alignment tricks here,
    215   // please.
    216 #pragma pack(push,1)
    217   // Header that is written to disk.
    218   struct BrowserThemePackHeader {
    219     // Numeric version to make sure we're compatible in the future.
    220     int32 version;
    221 
    222     // 1 if little_endian. 0 if big_endian. On mismatch, abort load.
    223     int32 little_endian;
    224 
    225     // theme_id without NULL terminator.
    226     uint8 theme_id[16];
    227   } *header_;
    228 
    229   // The remaining structs represent individual entries in an array. For the
    230   // following three structs, BrowserThemePack will either allocate an array or
    231   // will point directly to mmapped data.
    232   struct TintEntry {
    233     int32 id;
    234     double h;
    235     double s;
    236     double l;
    237   } *tints_;
    238 
    239   struct ColorPair {
    240     int32 id;
    241     SkColor color;
    242   } *colors_;
    243 
    244   struct DisplayPropertyPair {
    245     int32 id;
    246     int32 property;
    247   } *display_properties_;
    248 
    249   // A list of included source images. A pointer to a -1 terminated array of
    250   // our persistent IDs.
    251   int* source_images_;
    252 #pragma pack(pop)
    253 
    254   // The scale factors represented by the images in the theme pack.
    255   std::vector<ui::ScaleFactor> scale_factors_;
    256 
    257   // References to raw PNG data. This map isn't touched when |data_pack_| is
    258   // non-NULL; |image_memory_| is only filled during BuildFromExtension(). Any
    259   // image data that needs to be written to the DataPack during WriteToDisk()
    260   // needs to be in |image_memory_|.
    261   RawImages image_memory_;
    262 
    263   // Loaded images. These are loaded from |image_memory_|, from |data_pack_|,
    264   // and by BuildFromExtension(). These images should only be accessed on the UI
    265   // thread.
    266   ImageCache images_on_ui_thread_;
    267 
    268   // Cache of images created in BuildFromExtension(). Once the theme pack is
    269   // created, this cache should only be accessed on the file thread. There
    270   // should be no IDs in |image_memory_| that are in |images_on_file_thread_|
    271   // or vice versa.
    272   ImageCache images_on_file_thread_;
    273 
    274   DISALLOW_COPY_AND_ASSIGN(BrowserThemePack);
    275 };
    276 
    277 #endif  // CHROME_BROWSER_THEMES_BROWSER_THEME_PACK_H_
    278