browser_theme_pack.h revision dc0f95d653279beabeb9817299e2902918ba123e
1// Copyright (c) 2010 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/scoped_ptr.h"
14#include "base/ref_counted.h"
15#include "chrome/common/extensions/extension.h"
16#include "content/browser/browser_thread.h"
17#include "ui/gfx/color_utils.h"
18
19class DictionaryValue;
20class FilePath;
21class RefCountedMemory;
22namespace ui {
23class 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.
43class 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                               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