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
;
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();
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
);
45 *error
= base::ASCIIToUTF16(errors::kInvalidThemeImages
);
48 } else if (!iter
.value().IsType(base::Value::TYPE_STRING
)) {
49 *error
= base::ASCIIToUTF16(errors::kInvalidThemeImages
);
53 theme_info
->theme_images_
.reset(images_value
->DeepCopy());
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();
66 const base::ListValue
* color_list
= NULL
;
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
);
85 theme_info
->theme_colors_
.reset(colors_value
->DeepCopy());
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
))
97 // Validate that the tints are all reals.
98 for (base::DictionaryValue::Iterator
iter(*tints_value
); !iter
.IsAtEnd();
100 const base::ListValue
* tint_list
= NULL
;
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
);
111 theme_info
->theme_tints_
.reset(tints_value
->DeepCopy());
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());
127 const ThemeInfo
* GetInfo(const Extension
* extension
) {
128 return static_cast<ThemeInfo
*>(extension
->GetManifestData(keys::kTheme
));
133 ThemeInfo::ThemeInfo() {
136 ThemeInfo::~ThemeInfo() {
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
;
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
;
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
;
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
);
177 scoped_ptr
<ThemeInfo
> theme_info(new ThemeInfo
);
178 if (!LoadImages(theme_value
, error
, theme_info
.get()))
180 if (!LoadColors(theme_value
, error
, theme_info
.get()))
182 if (!LoadTints(theme_value
, error
, theme_info
.get()))
184 if (!LoadDisplayProperties(theme_value
, error
, theme_info
.get()))
187 extension
->SetManifestData(keys::kTheme
, theme_info
.release());
191 bool ThemeHandler::Validate(const Extension
* extension
,
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
);
199 for (base::DictionaryValue::Iterator
iter(*images_value
); !iter
.IsAtEnd();
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
)) {
207 l10n_util::GetStringFUTF8(IDS_EXTENSION_INVALID_IMAGE_PATH
,
208 image_path
.LossyDisplayName());
218 const std::vector
<std::string
> ThemeHandler::Keys() const {
219 return SingleKey(keys::kTheme
);
222 } // namespace extensions