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