Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2011 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/extension_page_actions_module.h"
      6 
      7 #include <string>
      8 
      9 #include "base/string_number_conversions.h"
     10 #include "chrome/browser/extensions/extension_page_actions_module_constants.h"
     11 #include "chrome/browser/extensions/extension_service.h"
     12 #include "chrome/browser/extensions/extension_tab_helper.h"
     13 #include "chrome/browser/extensions/extension_tabs_module.h"
     14 #include "chrome/browser/profiles/profile.h"
     15 #include "chrome/browser/ui/browser_list.h"
     16 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
     17 #include "chrome/common/extensions/extension.h"
     18 #include "chrome/common/extensions/extension_action.h"
     19 #include "chrome/common/extensions/extension_error_utils.h"
     20 #include "chrome/common/render_messages.h"
     21 #include "content/browser/tab_contents/navigation_entry.h"
     22 #include "content/browser/tab_contents/tab_contents.h"
     23 
     24 namespace keys = extension_page_actions_module_constants;
     25 
     26 namespace {
     27 // Errors.
     28 const char kNoTabError[] = "No tab with id: *.";
     29 const char kNoPageActionError[] =
     30     "This extension has no page action specified.";
     31 const char kUrlNotActiveError[] = "This url is no longer active: *.";
     32 const char kIconIndexOutOfBounds[] = "Page action icon index out of bounds.";
     33 const char kNoIconSpecified[] = "Page action has no icons to show.";
     34 }
     35 
     36 // TODO(EXTENSIONS_DEPRECATED): obsolete API.
     37 bool PageActionFunction::SetPageActionEnabled(bool enable) {
     38   std::string page_action_id;
     39   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &page_action_id));
     40   DictionaryValue* action;
     41   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &action));
     42 
     43   int tab_id;
     44   EXTENSION_FUNCTION_VALIDATE(action->GetInteger(keys::kTabIdKey, &tab_id));
     45   std::string url;
     46   EXTENSION_FUNCTION_VALIDATE(action->GetString(keys::kUrlKey, &url));
     47 
     48   std::string title;
     49   int icon_id = 0;
     50   if (enable) {
     51     // Both of those are optional.
     52     if (action->HasKey(keys::kTitleKey))
     53       EXTENSION_FUNCTION_VALIDATE(action->GetString(keys::kTitleKey, &title));
     54     if (action->HasKey(keys::kIconIdKey)) {
     55       EXTENSION_FUNCTION_VALIDATE(action->GetInteger(keys::kIconIdKey,
     56                                                      &icon_id));
     57     }
     58   }
     59 
     60   ExtensionAction* page_action = GetExtension()->page_action();
     61   if (!page_action) {
     62     error_ = kNoPageActionError;
     63     return false;
     64   }
     65 
     66   if (icon_id < 0 ||
     67       static_cast<size_t>(icon_id) >= page_action->icon_paths()->size()) {
     68     error_ = (icon_id == 0) ? kNoIconSpecified : kIconIndexOutOfBounds;
     69     return false;
     70   }
     71 
     72   // Find the TabContents that contains this tab id.
     73   TabContentsWrapper* contents = NULL;
     74   bool result = ExtensionTabUtil::GetTabById(
     75       tab_id, profile(), include_incognito(), NULL, NULL, &contents, NULL);
     76   if (!result || !contents) {
     77     error_ = ExtensionErrorUtils::FormatErrorMessage(
     78         kNoTabError, base::IntToString(tab_id));
     79     return false;
     80   }
     81 
     82   // Make sure the URL hasn't changed.
     83   NavigationEntry* entry = contents->controller().GetActiveEntry();
     84   if (!entry || url != entry->url().spec()) {
     85     error_ = ExtensionErrorUtils::FormatErrorMessage(kUrlNotActiveError, url);
     86     return false;
     87   }
     88 
     89   // Set visibility and broadcast notifications that the UI should be updated.
     90   page_action->SetIsVisible(tab_id, enable);
     91   page_action->SetTitle(tab_id, title);
     92   page_action->SetIconIndex(tab_id, icon_id);
     93   contents->extension_tab_helper()->PageActionStateChanged();
     94 
     95   return true;
     96 }
     97 
     98 bool PageActionFunction::InitCommon(int tab_id) {
     99   page_action_ = GetExtension()->page_action();
    100   if (!page_action_) {
    101     error_ = kNoPageActionError;
    102     return false;
    103   }
    104 
    105   // Find the TabContents that contains this tab id.
    106   contents_ = NULL;
    107   TabContentsWrapper* wrapper = NULL;
    108   bool result = ExtensionTabUtil::GetTabById(
    109       tab_id, profile(), include_incognito(), NULL, NULL, &wrapper, NULL);
    110   if (!result || !wrapper) {
    111     error_ = ExtensionErrorUtils::FormatErrorMessage(
    112         kNoTabError, base::IntToString(tab_id));
    113     return false;
    114   }
    115   contents_ = wrapper;
    116 
    117   return true;
    118 }
    119 
    120 bool PageActionFunction::SetVisible(bool visible) {
    121   int tab_id;
    122   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
    123   if (!InitCommon(tab_id))
    124     return false;
    125 
    126   page_action_->SetIsVisible(tab_id, visible);
    127   contents_->extension_tab_helper()->PageActionStateChanged();
    128   return true;
    129 }
    130 
    131 bool EnablePageActionFunction::RunImpl() {
    132   return SetPageActionEnabled(true);
    133 }
    134 
    135 bool DisablePageActionFunction::RunImpl() {
    136   return SetPageActionEnabled(false);
    137 }
    138 
    139 bool PageActionShowFunction::RunImpl() {
    140   return SetVisible(true);
    141 }
    142 
    143 bool PageActionHideFunction::RunImpl() {
    144   return SetVisible(false);
    145 }
    146 
    147 bool PageActionSetIconFunction::RunImpl() {
    148   DictionaryValue* args;
    149   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
    150 
    151   int tab_id;
    152   EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
    153   if (!InitCommon(tab_id))
    154     return false;
    155 
    156   // setIcon can take a variant argument: either a canvas ImageData, or an
    157   // icon index.
    158   BinaryValue* binary;
    159   int icon_index;
    160   if (args->GetBinary("imageData", &binary)) {
    161     IPC::Message bitmap_pickle(binary->GetBuffer(), binary->GetSize());
    162     void* iter = NULL;
    163     scoped_ptr<SkBitmap> bitmap(new SkBitmap);
    164     EXTENSION_FUNCTION_VALIDATE(
    165         IPC::ReadParam(&bitmap_pickle, &iter, bitmap.get()));
    166     page_action_->SetIcon(tab_id, *bitmap);
    167   } else if (args->GetInteger("iconIndex", &icon_index)) {
    168     if (icon_index < 0 || static_cast<size_t>(icon_index) >=
    169                               page_action_->icon_paths()->size()) {
    170       error_ = kIconIndexOutOfBounds;
    171       return false;
    172     }
    173     page_action_->SetIcon(tab_id, SkBitmap());
    174     page_action_->SetIconIndex(tab_id, icon_index);
    175   } else {
    176     EXTENSION_FUNCTION_VALIDATE(false);
    177   }
    178 
    179   contents_->extension_tab_helper()->PageActionStateChanged();
    180   return true;
    181 }
    182 
    183 bool PageActionSetTitleFunction::RunImpl() {
    184   DictionaryValue* args;
    185   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
    186 
    187   int tab_id;
    188   EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
    189   if (!InitCommon(tab_id))
    190     return false;
    191 
    192   std::string title;
    193   EXTENSION_FUNCTION_VALIDATE(args->GetString("title", &title));
    194 
    195   page_action_->SetTitle(tab_id, title);
    196   contents_->extension_tab_helper()->PageActionStateChanged();
    197   return true;
    198 }
    199 
    200 bool PageActionSetPopupFunction::RunImpl() {
    201   DictionaryValue* args;
    202   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
    203 
    204   int tab_id;
    205   EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
    206   if (!InitCommon(tab_id))
    207     return false;
    208 
    209   // TODO(skerner): Consider allowing null and undefined to mean the popup
    210   // should be removed.
    211   std::string popup_string;
    212   EXTENSION_FUNCTION_VALIDATE(args->GetString("popup", &popup_string));
    213 
    214   GURL popup_url;
    215   if (!popup_string.empty())
    216     popup_url = GetExtension()->GetResourceURL(popup_string);
    217 
    218   page_action_->SetPopupUrl(tab_id, popup_url);
    219   contents_->extension_tab_helper()->PageActionStateChanged();
    220   return true;
    221 }
    222 
    223 // Not currently exposed to extensions. To re-enable, add mapping in
    224 // extension_function_dispatcher.
    225 bool PageActionSetBadgeBackgroundColorFunction::RunImpl() {
    226   DictionaryValue* args;
    227   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
    228 
    229   int tab_id;
    230   EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
    231   if (!InitCommon(tab_id))
    232     return false;
    233 
    234   ListValue* color_value;
    235   EXTENSION_FUNCTION_VALIDATE(args->GetList("color", &color_value));
    236   EXTENSION_FUNCTION_VALIDATE(color_value->GetSize() == 4);
    237 
    238   int color_array[4] = {0};
    239   for (size_t i = 0; i < arraysize(color_array); ++i)
    240     EXTENSION_FUNCTION_VALIDATE(color_value->GetInteger(i, &color_array[i]));
    241 
    242   SkColor color = SkColorSetARGB(color_array[3], color_array[0], color_array[1],
    243                                  color_array[2]);
    244   page_action_->SetBadgeBackgroundColor(tab_id, color);
    245   contents_->extension_tab_helper()->PageActionStateChanged();
    246   return true;
    247 }
    248 
    249 // Not currently exposed to extensions. To re-enable, add mapping in
    250 // extension_function_dispatcher.
    251 bool PageActionSetBadgeTextColorFunction::RunImpl() {
    252   DictionaryValue* args;
    253   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
    254 
    255   int tab_id;
    256   EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
    257   if (!InitCommon(tab_id))
    258     return false;
    259 
    260   ListValue* color_value;
    261   EXTENSION_FUNCTION_VALIDATE(args->GetList("color", &color_value));
    262   EXTENSION_FUNCTION_VALIDATE(color_value->GetSize() == 4);
    263 
    264   int color_array[4] = {0};
    265   for (size_t i = 0; i < arraysize(color_array); ++i)
    266     EXTENSION_FUNCTION_VALIDATE(color_value->GetInteger(i, &color_array[i]));
    267 
    268   SkColor color = SkColorSetARGB(color_array[3], color_array[0], color_array[1],
    269                                  color_array[2]);
    270   page_action_->SetBadgeTextColor(tab_id, color);
    271   contents_->extension_tab_helper()->PageActionStateChanged();
    272   return true;
    273 }
    274 
    275 // Not currently exposed to extensions. To re-enable, add mapping in
    276 // extension_function_dispatcher.
    277 bool PageActionSetBadgeTextFunction::RunImpl() {
    278   DictionaryValue* args;
    279   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
    280 
    281   int tab_id;
    282   EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
    283   if (!InitCommon(tab_id))
    284     return false;
    285 
    286   std::string text;
    287   EXTENSION_FUNCTION_VALIDATE(args->GetString("text", &text));
    288 
    289   page_action_->SetBadgeText(tab_id, text);
    290   contents_->extension_tab_helper()->PageActionStateChanged();
    291   return true;
    292 }
    293