Home | History | Annotate | Download | only in themes
      1 // Copyright (c) 2011 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 #pragma once
      8 
      9 #include <map>
     10 #include <string>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/memory/ref_counted.h"
     14 #include "base/memory/scoped_ptr.h"
     15 #include "chrome/common/extensions/extension.h"
     16 #include "content/browser/browser_thread.h"
     17 #include "ui/gfx/color_utils.h"
     18 
     19 class DictionaryValue;
     20 class FilePath;
     21 class RefCountedMemory;
     22 namespace ui {
     23 class DataPack;
     24 }
     25 
     26 // An optimized representation of a theme, backed by a mmapped DataPack.
     27 //
     28 // The idea is to pre-process all images (tinting, compositing, etc) at theme
     29 // install time, save all the PNG-ified data into an mmappable file so we don't
     30 // suffer multiple file system access times, therefore solving two of the
     31 // problems with the previous implementation.
     32 //
     33 // A note on const-ness. All public, non-static methods are const.  We do this
     34 // because once we've constructed a BrowserThemePack through the
     35 // BuildFromExtension() interface, we WriteToDisk() on a thread other than the
     36 // UI thread that consumes a BrowserThemePack. There is no locking; thread
     37 // safety between the writing thread and the UI thread is ensured by having the
     38 // data be immutable.
     39 //
     40 // BrowserThemePacks are always deleted on the file thread because in the
     41 // common case, they are backed by mmapped data and the unmmapping operation
     42 // will trip our IO on the UI thread detector.
     43 class BrowserThemePack : public base::RefCountedThreadSafe<
     44     BrowserThemePack, BrowserThread::DeleteOnFileThread> {
     45  public:
     46   // Builds the theme pack from all data from |extension|. This is often done
     47   // on a separate thread as it takes so long. This can fail and return NULL in
     48   // the case where the theme has invalid data.
     49   static BrowserThemePack* BuildFromExtension(const Extension* extension);
     50 
     51   // Builds the theme pack from a previously performed WriteToDisk(). This
     52   // operation should be relatively fast, as it should be an mmap() and some
     53   // pointer swizzling. Returns NULL on any error attempting to read |path|.
     54   static scoped_refptr<BrowserThemePack> BuildFromDataPack(
     55       FilePath path, const std::string& expected_id);
     56 
     57   // Builds a data pack on disk at |path| for future quick loading by
     58   // BuildFromDataPack(). Often (but not always) called from the file thread;
     59   // implementation should be threadsafe because neither thread will write to
     60   // |image_memory_| and the worker thread will keep a reference to prevent
     61   // destruction.
     62   bool WriteToDisk(FilePath path) const;
     63 
     64   // If this theme specifies data for the corresponding |id|, return true and
     65   // write the corresponding value to the output parameter. These functions
     66   // don't return the default data. These methods should only be called from
     67   // the UI thread. (But this isn't enforced because of unit tests).
     68   bool GetTint(int id, color_utils::HSL* hsl) const;
     69   bool GetColor(int id, SkColor* color) const;
     70   bool GetDisplayProperty(int id, int* result) const;
     71 
     72   // Returns a bitmap if we have a custom image for |id|, otherwise NULL. Note
     73   // that this is separate from HasCustomImage() which returns whether a custom
     74   // image |id| was included in the unprocessed theme and is used as a proxy
     75   // for making layout decisions in the interface.
     76   SkBitmap* GetBitmapNamed(int id) const;
     77 
     78   // Returns the raw PNG encoded data for IDR_THEME_NTP_*. This method is only
     79   // supposed to work for the NTP attribution and background resources.
     80   RefCountedMemory* GetRawData(int id) const;
     81 
     82   // Whether this theme provides an image for |id|.
     83   bool HasCustomImage(int id) const;
     84 
     85  private:
     86   friend struct BrowserThread::DeleteOnThread<BrowserThread::FILE>;
     87   friend class DeleteTask<BrowserThemePack>;
     88   friend class BrowserThemePackTest;
     89 
     90   // Cached images. We cache all retrieved and generated bitmaps and keep
     91   // track of the pointers. We own these and will delete them when we're done
     92   // using them.
     93   typedef std::map<int, SkBitmap*> ImageCache;
     94 
     95   // The raw PNG memory associated with a certain id.
     96   typedef std::map<int, scoped_refptr<RefCountedMemory> > RawImages;
     97 
     98   // The type passed to base::DataPack::WritePack.
     99   typedef std::map<uint32, base::StringPiece> RawDataForWriting;
    100 
    101   // An association between an id and the FilePath that has the image data.
    102   typedef std::map<int, FilePath> FilePathMap;
    103 
    104   // Default. Everything is empty.
    105   BrowserThemePack();
    106 
    107   virtual ~BrowserThemePack();
    108 
    109   // Builds a header ready to write to disk.
    110   void BuildHeader(const Extension* extension);
    111 
    112   // Transforms the JSON tint values into their final versions in the |tints_|
    113   // array.
    114   void BuildTintsFromJSON(DictionaryValue* tints_value);
    115 
    116   // Transforms the JSON color values into their final versions in the
    117   // |colors_| array and also fills in unspecified colors based on tint values.
    118   void BuildColorsFromJSON(DictionaryValue* color_value);
    119 
    120   // Implementation details of BuildColorsFromJSON().
    121   void ReadColorsFromJSON(DictionaryValue* colors_value,
    122                           std::map<int, SkColor>* temp_colors);
    123   void GenerateMissingColors(std::map<int, SkColor>* temp_colors);
    124 
    125   // Transforms the JSON display properties into |display_properties_|.
    126   void BuildDisplayPropertiesFromJSON(DictionaryValue* display_value);
    127 
    128   // Parses the image names out of an extension.
    129   void ParseImageNamesFromJSON(DictionaryValue* images_value,
    130                                const FilePath& images_path,
    131                                FilePathMap* file_paths) const;
    132 
    133   // Creates the data for |source_images_| from |file_paths|.
    134   void BuildSourceImagesArray(const FilePathMap& file_paths);
    135 
    136   // Loads the unmodified bitmaps packed in the extension to SkBitmaps. Returns
    137   // true if all images loaded.
    138   bool LoadRawBitmapsTo(const FilePathMap& file_paths,
    139                         ImageCache* raw_bitmaps);
    140 
    141   // Creates tinted and composited frame images. Source and destination is
    142   // |bitmaps|.
    143   void GenerateFrameImages(ImageCache* bitmaps) const;
    144 
    145   // Generates button images tinted with |button_tint| and places them in
    146   // processed_bitmaps.
    147   void GenerateTintedButtons(const color_utils::HSL& button_tint,
    148                              ImageCache* processed_bitmaps) const;
    149 
    150   // Generates the semi-transparent tab background images, putting the results
    151   // in |bitmaps|. Must be called after GenerateFrameImages().
    152   void GenerateTabBackgroundImages(ImageCache* bitmaps) const;
    153 
    154   // Takes all the SkBitmaps in |images|, encodes them as PNGs and places
    155   // them in |reencoded_images|.
    156   void RepackImages(const ImageCache& images,
    157                     RawImages* reencoded_images) const;
    158 
    159   // Takes all images in |source| and puts them in |destination|, freeing any
    160   // image already in |destination| that |source| would overwrite.
    161   void MergeImageCaches(const ImageCache& source,
    162                         ImageCache* destination) const;
    163 
    164   // Changes the RefCountedMemory based |images| into StringPiece data in |out|.
    165   void AddRawImagesTo(const RawImages& images, RawDataForWriting* out) const;
    166 
    167   // Retrieves the tint OR the default tint. Unlike the public interface, we
    168   // always need to return a reasonable tint here, instead of partially
    169   // querying if the tint exists.
    170   color_utils::HSL GetTintInternal(int id) const;
    171 
    172   // Data pack, if we have one.
    173   scoped_ptr<ui::DataPack> data_pack_;
    174 
    175   // All structs written to disk need to be packed; no alignment tricks here,
    176   // please.
    177 #pragma pack(push,1)
    178   // Header that is written to disk.
    179   struct BrowserThemePackHeader {
    180     // Numeric version to make sure we're compatible in the future.
    181     int32 version;
    182 
    183     // 1 if little_endian. 0 if big_endian. On mismatch, abort load.
    184     int32 little_endian;
    185 
    186     // theme_id without NULL terminator.
    187     uint8 theme_id[16];
    188   } *header_;
    189 
    190   // The remaining structs represent individual entries in an array. For the
    191   // following three structs, BrowserThemePack will either allocate an array or
    192   // will point directly to mmapped data.
    193   struct TintEntry {
    194     int32 id;
    195     double h;
    196     double s;
    197     double l;
    198   } *tints_;
    199 
    200   struct ColorPair {
    201     int32 id;
    202     SkColor color;
    203   } *colors_;
    204 
    205   struct DisplayPropertyPair {
    206     int32 id;
    207     int32 property;
    208   } *display_properties_;
    209 
    210   // A list of included source images. A pointer to a -1 terminated array of
    211   // our persistent IDs.
    212   int* source_images_;
    213 #pragma pack(pop)
    214 
    215   // References to raw PNG data. This map isn't touched when |data_pack_| is
    216   // non-NULL; |image_memory_| is only filled during BuildFromExtension(). Any
    217   // image data that needs to be written to the DataPack during WriteToDisk()
    218   // needs to be in |image_memory_|.
    219   RawImages image_memory_;
    220 
    221   // An immutable cache of images generated in BuildFromExtension(). When this
    222   // BrowserThemePack is generated from BuildFromDataPack(), this cache is
    223   // empty. We separate the images from the images loaded from disk so that
    224   // WriteToDisk()'s implementation doesn't need locks. There should be no IDs
    225   // in |image_memory_| that are in |prepared_images_| or vice versa.
    226   ImageCache prepared_images_;
    227 
    228   // Loaded images. These are loaded from |image_memory_| or the |data_pack_|.
    229   mutable ImageCache loaded_images_;
    230 
    231   DISALLOW_COPY_AND_ASSIGN(BrowserThemePack);
    232 };
    233 
    234 #endif  // CHROME_BROWSER_THEMES_BROWSER_THEME_PACK_H_
    235