1 // Copyright (c) 2012 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/browser/extensions/api/declarative_content/content_action.h" 6 7 #include <map> 8 9 #include "base/lazy_instance.h" 10 #include "base/strings/stringprintf.h" 11 #include "base/values.h" 12 #include "chrome/browser/extensions/api/declarative_content/content_constants.h" 13 #include "chrome/browser/extensions/extension_action.h" 14 #include "chrome/browser/extensions/extension_action_manager.h" 15 #include "chrome/browser/extensions/extension_tab_util.h" 16 #include "chrome/browser/profiles/profile.h" 17 #include "content/public/browser/invalidate_type.h" 18 #include "content/public/browser/web_contents.h" 19 #include "extensions/browser/extension_registry.h" 20 #include "extensions/common/extension.h" 21 22 namespace extensions { 23 24 namespace keys = declarative_content_constants; 25 26 namespace { 27 // Error messages. 28 const char kInvalidInstanceTypeError[] = 29 "An action has an invalid instanceType: %s"; 30 const char kNoPageAction[] = 31 "Can't use declarativeContent.ShowPageAction without a page action"; 32 33 #define INPUT_FORMAT_VALIDATE(test) do { \ 34 if (!(test)) { \ 35 *bad_message = true; \ 36 return scoped_refptr<ContentAction>(NULL); \ 37 } \ 38 } while (0) 39 40 // 41 // The following are concrete actions. 42 // 43 44 // Action that instructs to show an extension's page action. 45 class ShowPageAction : public ContentAction { 46 public: 47 ShowPageAction() {} 48 49 static scoped_refptr<ContentAction> Create(const Extension* extension, 50 const base::DictionaryValue* dict, 51 std::string* error, 52 bool* bad_message) { 53 // We can't show a page action if the extension doesn't have one. 54 if (ActionInfo::GetPageActionInfo(extension) == NULL) { 55 *error = kNoPageAction; 56 return scoped_refptr<ContentAction>(); 57 } 58 return scoped_refptr<ContentAction>(new ShowPageAction); 59 } 60 61 // Implementation of ContentAction: 62 virtual Type GetType() const OVERRIDE { return ACTION_SHOW_PAGE_ACTION; } 63 virtual void Apply(const std::string& extension_id, 64 const base::Time& extension_install_time, 65 ApplyInfo* apply_info) const OVERRIDE { 66 GetPageAction(apply_info->profile, extension_id)->DeclarativeShow( 67 ExtensionTabUtil::GetTabId(apply_info->tab)); 68 apply_info->tab->NotifyNavigationStateChanged( 69 content::INVALIDATE_TYPE_PAGE_ACTIONS); 70 } 71 virtual void Revert(const std::string& extension_id, 72 const base::Time& extension_install_time, 73 ApplyInfo* apply_info) const OVERRIDE { 74 if (ExtensionAction* action = 75 GetPageAction(apply_info->profile, extension_id)) { 76 action->UndoDeclarativeShow(ExtensionTabUtil::GetTabId(apply_info->tab)); 77 apply_info->tab->NotifyNavigationStateChanged( 78 content::INVALIDATE_TYPE_PAGE_ACTIONS); 79 } 80 } 81 82 private: 83 static ExtensionAction* GetPageAction(Profile* profile, 84 const std::string& extension_id) { 85 const Extension* extension = 86 ExtensionRegistry::Get(profile) 87 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING); 88 if (!extension) 89 return NULL; 90 return ExtensionActionManager::Get(profile)->GetPageAction(*extension); 91 } 92 virtual ~ShowPageAction() {} 93 94 DISALLOW_COPY_AND_ASSIGN(ShowPageAction); 95 }; 96 97 struct ContentActionFactory { 98 // Factory methods for ContentAction instances. |extension| is the extension 99 // for which the action is being created. |dict| contains the json dictionary 100 // that describes the action. |error| is used to return error messages in case 101 // the extension passed an action that was syntactically correct but 102 // semantically incorrect. |bad_message| is set to true in case |dict| does 103 // not confirm to the validated JSON specification. 104 typedef scoped_refptr<ContentAction>(*FactoryMethod)( 105 const Extension* /* extension */, 106 const base::DictionaryValue* /* dict */, 107 std::string* /* error */, 108 bool* /* bad_message */); 109 // Maps the name of a declarativeContent action type to the factory 110 // function creating it. 111 std::map<std::string, FactoryMethod> factory_methods; 112 113 ContentActionFactory() { 114 factory_methods[keys::kShowPageAction] = 115 &ShowPageAction::Create; 116 } 117 }; 118 119 base::LazyInstance<ContentActionFactory>::Leaky 120 g_content_action_factory = LAZY_INSTANCE_INITIALIZER; 121 122 } // namespace 123 124 // 125 // ContentAction 126 // 127 128 ContentAction::ContentAction() {} 129 130 ContentAction::~ContentAction() {} 131 132 // static 133 scoped_refptr<ContentAction> ContentAction::Create( 134 const Extension* extension, 135 const base::Value& json_action, 136 std::string* error, 137 bool* bad_message) { 138 *error = ""; 139 *bad_message = false; 140 141 const base::DictionaryValue* action_dict = NULL; 142 INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(&action_dict)); 143 144 std::string instance_type; 145 INPUT_FORMAT_VALIDATE( 146 action_dict->GetString(keys::kInstanceType, &instance_type)); 147 148 ContentActionFactory& factory = g_content_action_factory.Get(); 149 std::map<std::string, ContentActionFactory::FactoryMethod>::iterator 150 factory_method_iter = factory.factory_methods.find(instance_type); 151 if (factory_method_iter != factory.factory_methods.end()) 152 return (*factory_method_iter->second)( 153 extension, action_dict, error, bad_message); 154 155 *error = base::StringPrintf(kInvalidInstanceTypeError, instance_type.c_str()); 156 return scoped_refptr<ContentAction>(); 157 } 158 159 } // namespace extensions 160