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