Home | History | Annotate | Download | only in declarative_content
      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