• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013 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 #include "chrome/common/extensions/manifest_handlers/theme_handler.h"
6 
7 #include "base/files/file_util.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/values.h"
11 #include "chrome/grit/generated_resources.h"
12 #include "extensions/common/manifest.h"
13 #include "extensions/common/manifest_constants.h"
14 #include "ui/base/l10n/l10n_util.h"
15 
16 namespace extensions {
17 
18 namespace keys = manifest_keys;
19 namespace errors = manifest_errors;
20 
21 namespace {
22 
LoadImages(const base::DictionaryValue * theme_value,base::string16 * error,ThemeInfo * theme_info)23 bool LoadImages(const base::DictionaryValue* theme_value,
24                 base::string16* error,
25                 ThemeInfo* theme_info) {
26   const base::DictionaryValue* images_value = NULL;
27   if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) {
28     // Validate that the images are all strings.
29     for (base::DictionaryValue::Iterator iter(*images_value); !iter.IsAtEnd();
30          iter.Advance()) {
31       // The value may be a dictionary of scales and files paths.
32       // Or the value may be a file path, in which case a scale
33       // of 100% is assumed.
34       if (iter.value().IsType(base::Value::TYPE_DICTIONARY)) {
35         const base::DictionaryValue* inner_value = NULL;
36         if (iter.value().GetAsDictionary(&inner_value)) {
37           for (base::DictionaryValue::Iterator inner_iter(*inner_value);
38                !inner_iter.IsAtEnd(); inner_iter.Advance()) {
39             if (!inner_iter.value().IsType(base::Value::TYPE_STRING)) {
40               *error = base::ASCIIToUTF16(errors::kInvalidThemeImages);
41               return false;
42             }
43           }
44         } else {
45           *error = base::ASCIIToUTF16(errors::kInvalidThemeImages);
46           return false;
47         }
48       } else if (!iter.value().IsType(base::Value::TYPE_STRING)) {
49         *error = base::ASCIIToUTF16(errors::kInvalidThemeImages);
50         return false;
51       }
52     }
53     theme_info->theme_images_.reset(images_value->DeepCopy());
54   }
55   return true;
56 }
57 
LoadColors(const base::DictionaryValue * theme_value,base::string16 * error,ThemeInfo * theme_info)58 bool LoadColors(const base::DictionaryValue* theme_value,
59                 base::string16* error,
60                 ThemeInfo* theme_info) {
61   const base::DictionaryValue* colors_value = NULL;
62   if (theme_value->GetDictionary(keys::kThemeColors, &colors_value)) {
63     // Validate that the colors are RGB or RGBA lists.
64     for (base::DictionaryValue::Iterator iter(*colors_value); !iter.IsAtEnd();
65          iter.Advance()) {
66       const base::ListValue* color_list = NULL;
67       double alpha = 0.0;
68       int color = 0;
69       // The color must be a list...
70       if (!iter.value().GetAsList(&color_list) ||
71           // ... and either 3 items (RGB) or 4 (RGBA).
72           ((color_list->GetSize() != 3) &&
73            ((color_list->GetSize() != 4) ||
74             // For RGBA, the fourth item must be a real or int alpha value.
75             // Note that GetDouble() can get an integer value.
76             !color_list->GetDouble(3, &alpha))) ||
77           // For both RGB and RGBA, the first three items must be ints (R,G,B).
78           !color_list->GetInteger(0, &color) ||
79           !color_list->GetInteger(1, &color) ||
80           !color_list->GetInteger(2, &color)) {
81         *error = base::ASCIIToUTF16(errors::kInvalidThemeColors);
82         return false;
83       }
84     }
85     theme_info->theme_colors_.reset(colors_value->DeepCopy());
86   }
87   return true;
88 }
89 
LoadTints(const base::DictionaryValue * theme_value,base::string16 * error,ThemeInfo * theme_info)90 bool LoadTints(const base::DictionaryValue* theme_value,
91                base::string16* error,
92                ThemeInfo* theme_info) {
93   const base::DictionaryValue* tints_value = NULL;
94   if (!theme_value->GetDictionary(keys::kThemeTints, &tints_value))
95     return true;
96 
97   // Validate that the tints are all reals.
98   for (base::DictionaryValue::Iterator iter(*tints_value); !iter.IsAtEnd();
99        iter.Advance()) {
100     const base::ListValue* tint_list = NULL;
101     double v = 0.0;
102     if (!iter.value().GetAsList(&tint_list) ||
103         tint_list->GetSize() != 3 ||
104         !tint_list->GetDouble(0, &v) ||
105         !tint_list->GetDouble(1, &v) ||
106         !tint_list->GetDouble(2, &v)) {
107       *error = base::ASCIIToUTF16(errors::kInvalidThemeTints);
108       return false;
109     }
110   }
111   theme_info->theme_tints_.reset(tints_value->DeepCopy());
112   return true;
113 }
114 
LoadDisplayProperties(const base::DictionaryValue * theme_value,base::string16 * error,ThemeInfo * theme_info)115 bool LoadDisplayProperties(const base::DictionaryValue* theme_value,
116                            base::string16* error,
117                            ThemeInfo* theme_info) {
118   const base::DictionaryValue* display_properties_value = NULL;
119   if (theme_value->GetDictionary(keys::kThemeDisplayProperties,
120                                  &display_properties_value)) {
121     theme_info->theme_display_properties_.reset(
122         display_properties_value->DeepCopy());
123   }
124   return true;
125 }
126 
GetInfo(const Extension * extension)127 const ThemeInfo* GetInfo(const Extension* extension) {
128   return static_cast<ThemeInfo*>(extension->GetManifestData(keys::kTheme));
129 }
130 
131 }  // namespace
132 
ThemeInfo()133 ThemeInfo::ThemeInfo() {
134 }
135 
~ThemeInfo()136 ThemeInfo::~ThemeInfo() {
137 }
138 
139 // static
GetImages(const Extension * extension)140 const base::DictionaryValue* ThemeInfo::GetImages(const Extension* extension) {
141   const ThemeInfo* theme_info = GetInfo(extension);
142   return theme_info ? theme_info->theme_images_.get() : NULL;
143 }
144 
145 // static
GetColors(const Extension * extension)146 const base::DictionaryValue* ThemeInfo::GetColors(const Extension* extension) {
147   const ThemeInfo* theme_info = GetInfo(extension);
148   return theme_info ? theme_info->theme_colors_.get() : NULL;
149 }
150 
151 // static
GetTints(const Extension * extension)152 const base::DictionaryValue* ThemeInfo::GetTints(const Extension* extension) {
153   const ThemeInfo* theme_info = GetInfo(extension);
154   return theme_info ? theme_info->theme_tints_.get() : NULL;
155 }
156 
157 // static
GetDisplayProperties(const Extension * extension)158 const base::DictionaryValue* ThemeInfo::GetDisplayProperties(
159     const Extension* extension) {
160   const ThemeInfo* theme_info = GetInfo(extension);
161   return theme_info ? theme_info->theme_display_properties_.get() : NULL;
162 }
163 
ThemeHandler()164 ThemeHandler::ThemeHandler() {
165 }
166 
~ThemeHandler()167 ThemeHandler::~ThemeHandler() {
168 }
169 
Parse(Extension * extension,base::string16 * error)170 bool ThemeHandler::Parse(Extension* extension, base::string16* error) {
171   const base::DictionaryValue* theme_value = NULL;
172   if (!extension->manifest()->GetDictionary(keys::kTheme, &theme_value)) {
173     *error = base::ASCIIToUTF16(errors::kInvalidTheme);
174     return false;
175   }
176 
177   scoped_ptr<ThemeInfo> theme_info(new ThemeInfo);
178   if (!LoadImages(theme_value, error, theme_info.get()))
179     return false;
180   if (!LoadColors(theme_value, error, theme_info.get()))
181     return false;
182   if (!LoadTints(theme_value, error, theme_info.get()))
183     return false;
184   if (!LoadDisplayProperties(theme_value, error, theme_info.get()))
185     return false;
186 
187   extension->SetManifestData(keys::kTheme, theme_info.release());
188   return true;
189 }
190 
Validate(const Extension * extension,std::string * error,std::vector<InstallWarning> * warnings) const191 bool ThemeHandler::Validate(const Extension* extension,
192                             std::string* error,
193                             std::vector<InstallWarning>* warnings) const {
194   // Validate that theme images exist.
195   if (extension->is_theme()) {
196     const base::DictionaryValue* images_value =
197         extensions::ThemeInfo::GetImages(extension);
198     if (images_value) {
199       for (base::DictionaryValue::Iterator iter(*images_value); !iter.IsAtEnd();
200            iter.Advance()) {
201         std::string val;
202         if (iter.value().GetAsString(&val)) {
203           base::FilePath image_path = extension->path().Append(
204               base::FilePath::FromUTF8Unsafe(val));
205           if (!base::PathExists(image_path)) {
206             *error =
207                 l10n_util::GetStringFUTF8(IDS_EXTENSION_INVALID_IMAGE_PATH,
208                                           image_path.LossyDisplayName());
209             return false;
210           }
211         }
212       }
213     }
214   }
215   return true;
216 }
217 
Keys() const218 const std::vector<std::string> ThemeHandler::Keys() const {
219   return SingleKey(keys::kTheme);
220 }
221 
222 }  // namespace extensions
223