Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / common / extensions / manifest_handlers / theme_handler.cc
blob5a4105f6467fa9b17aa61ef3290c02dca9e44190
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.
5 #include "chrome/common/extensions/manifest_handlers/theme_handler.h"
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"
16 namespace extensions {
18 namespace keys = manifest_keys;
19 namespace errors = manifest_errors;
21 namespace {
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;
44 } else {
45 *error = base::ASCIIToUTF16(errors::kInvalidThemeImages);
46 return false;
48 } else if (!iter.value().IsType(base::Value::TYPE_STRING)) {
49 *error = base::ASCIIToUTF16(errors::kInvalidThemeImages);
50 return false;
53 theme_info->theme_images_.reset(images_value->DeepCopy());
55 return true;
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;
85 theme_info->theme_colors_.reset(colors_value->DeepCopy());
87 return true;
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;
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;
111 theme_info->theme_tints_.reset(tints_value->DeepCopy());
112 return true;
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());
124 return true;
127 const ThemeInfo* GetInfo(const Extension* extension) {
128 return static_cast<ThemeInfo*>(extension->GetManifestData(keys::kTheme));
131 } // namespace
133 ThemeInfo::ThemeInfo() {
136 ThemeInfo::~ThemeInfo() {
139 // static
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;
145 // static
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;
151 // static
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;
157 // static
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;
164 ThemeHandler::ThemeHandler() {
167 ThemeHandler::~ThemeHandler() {
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;
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;
187 extension->SetManifestData(keys::kTheme, theme_info.release());
188 return true;
191 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;
215 return true;
218 const std::vector<std::string> ThemeHandler::Keys() const {
219 return SingleKey(keys::kTheme);
222 } // namespace extensions