// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/common/extensions/manifest_handlers/theme_handler.h" #include "base/file_util.h" #include "base/memory/scoped_ptr.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "extensions/common/manifest.h" #include "extensions/common/manifest_constants.h" #include "grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" namespace extensions { namespace keys = manifest_keys; namespace errors = manifest_errors; namespace { bool LoadImages(const base::DictionaryValue* theme_value, base::string16* error, ThemeInfo* theme_info) { const base::DictionaryValue* images_value = NULL; if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) { // Validate that the images are all strings. for (base::DictionaryValue::Iterator iter(*images_value); !iter.IsAtEnd(); iter.Advance()) { // The value may be a dictionary of scales and files paths. // Or the value may be a file path, in which case a scale // of 100% is assumed. if (iter.value().IsType(base::Value::TYPE_DICTIONARY)) { const base::DictionaryValue* inner_value = NULL; if (iter.value().GetAsDictionary(&inner_value)) { for (base::DictionaryValue::Iterator inner_iter(*inner_value); !inner_iter.IsAtEnd(); inner_iter.Advance()) { if (!inner_iter.value().IsType(base::Value::TYPE_STRING)) { *error = base::ASCIIToUTF16(errors::kInvalidThemeImages); return false; } } } else { *error = base::ASCIIToUTF16(errors::kInvalidThemeImages); return false; } } else if (!iter.value().IsType(base::Value::TYPE_STRING)) { *error = base::ASCIIToUTF16(errors::kInvalidThemeImages); return false; } } theme_info->theme_images_.reset(images_value->DeepCopy()); } return true; } bool LoadColors(const base::DictionaryValue* theme_value, base::string16* error, ThemeInfo* theme_info) { const base::DictionaryValue* colors_value = NULL; if (theme_value->GetDictionary(keys::kThemeColors, &colors_value)) { // Validate that the colors are RGB or RGBA lists. for (base::DictionaryValue::Iterator iter(*colors_value); !iter.IsAtEnd(); iter.Advance()) { const base::ListValue* color_list = NULL; double alpha = 0.0; int color = 0; // The color must be a list... if (!iter.value().GetAsList(&color_list) || // ... and either 3 items (RGB) or 4 (RGBA). ((color_list->GetSize() != 3) && ((color_list->GetSize() != 4) || // For RGBA, the fourth item must be a real or int alpha value. // Note that GetDouble() can get an integer value. !color_list->GetDouble(3, &alpha))) || // For both RGB and RGBA, the first three items must be ints (R,G,B). !color_list->GetInteger(0, &color) || !color_list->GetInteger(1, &color) || !color_list->GetInteger(2, &color)) { *error = base::ASCIIToUTF16(errors::kInvalidThemeColors); return false; } } theme_info->theme_colors_.reset(colors_value->DeepCopy()); } return true; } bool LoadTints(const base::DictionaryValue* theme_value, base::string16* error, ThemeInfo* theme_info) { const base::DictionaryValue* tints_value = NULL; if (!theme_value->GetDictionary(keys::kThemeTints, &tints_value)) return true; // Validate that the tints are all reals. for (base::DictionaryValue::Iterator iter(*tints_value); !iter.IsAtEnd(); iter.Advance()) { const base::ListValue* tint_list = NULL; double v = 0.0; if (!iter.value().GetAsList(&tint_list) || tint_list->GetSize() != 3 || !tint_list->GetDouble(0, &v) || !tint_list->GetDouble(1, &v) || !tint_list->GetDouble(2, &v)) { *error = base::ASCIIToUTF16(errors::kInvalidThemeTints); return false; } } theme_info->theme_tints_.reset(tints_value->DeepCopy()); return true; } bool LoadDisplayProperties(const base::DictionaryValue* theme_value, base::string16* error, ThemeInfo* theme_info) { const base::DictionaryValue* display_properties_value = NULL; if (theme_value->GetDictionary(keys::kThemeDisplayProperties, &display_properties_value)) { theme_info->theme_display_properties_.reset( display_properties_value->DeepCopy()); } return true; } const ThemeInfo* GetInfo(const Extension* extension) { return static_cast(extension->GetManifestData(keys::kTheme)); } } // namespace ThemeInfo::ThemeInfo() { } ThemeInfo::~ThemeInfo() { } // static const base::DictionaryValue* ThemeInfo::GetImages(const Extension* extension) { const ThemeInfo* theme_info = GetInfo(extension); return theme_info ? theme_info->theme_images_.get() : NULL; } // static const base::DictionaryValue* ThemeInfo::GetColors(const Extension* extension) { const ThemeInfo* theme_info = GetInfo(extension); return theme_info ? theme_info->theme_colors_.get() : NULL; } // static const base::DictionaryValue* ThemeInfo::GetTints(const Extension* extension) { const ThemeInfo* theme_info = GetInfo(extension); return theme_info ? theme_info->theme_tints_.get() : NULL; } // static const base::DictionaryValue* ThemeInfo::GetDisplayProperties( const Extension* extension) { const ThemeInfo* theme_info = GetInfo(extension); return theme_info ? theme_info->theme_display_properties_.get() : NULL; } ThemeHandler::ThemeHandler() { } ThemeHandler::~ThemeHandler() { } bool ThemeHandler::Parse(Extension* extension, base::string16* error) { const base::DictionaryValue* theme_value = NULL; if (!extension->manifest()->GetDictionary(keys::kTheme, &theme_value)) { *error = base::ASCIIToUTF16(errors::kInvalidTheme); return false; } scoped_ptr theme_info(new ThemeInfo); if (!LoadImages(theme_value, error, theme_info.get())) return false; if (!LoadColors(theme_value, error, theme_info.get())) return false; if (!LoadTints(theme_value, error, theme_info.get())) return false; if (!LoadDisplayProperties(theme_value, error, theme_info.get())) return false; extension->SetManifestData(keys::kTheme, theme_info.release()); return true; } bool ThemeHandler::Validate(const Extension* extension, std::string* error, std::vector* warnings) const { // Validate that theme images exist. if (extension->is_theme()) { const base::DictionaryValue* images_value = extensions::ThemeInfo::GetImages(extension); if (images_value) { for (base::DictionaryValue::Iterator iter(*images_value); !iter.IsAtEnd(); iter.Advance()) { std::string val; if (iter.value().GetAsString(&val)) { base::FilePath image_path = extension->path().Append( base::FilePath::FromUTF8Unsafe(val)); if (!base::PathExists(image_path)) { *error = l10n_util::GetStringFUTF8(IDS_EXTENSION_INVALID_IMAGE_PATH, image_path.LossyDisplayName()); return false; } } } } } return true; } const std::vector ThemeHandler::Keys() const { return SingleKey(keys::kTheme); } } // namespace extensions