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 21namespace base { 22class DictionaryValue; 23class FilePath; 24class RefCountedMemory; 25} 26 27namespace extensions { 28class Extensions; 29} 30 31namespace gfx { 32class Image; 33} 34 35namespace ui { 36class 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. 56class 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