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