15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_action.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/base64.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
12ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/badge_util.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/icon_with_badge_image_source.h"
15c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/constants.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h"
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "grit/ui_resources.h"
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ipc/ipc_message.h"
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ipc/ipc_message_utils.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkCanvas.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkPaint.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/effects/SkGradientShader.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
25d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/animation/animation_delegate.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/color_utils.h"
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/image/image.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image_skia_source.h"
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/gfx/ipc/gfx_param_traits.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/size.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/skbitmap_operations.h"
357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class GetAttentionImageSource : public gfx::ImageSkiaSource {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit GetAttentionImageSource(const gfx::ImageSkia& icon)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : icon_(icon) {}
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // gfx::ImageSkiaSource overrides:
4568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  virtual gfx::ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
4668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    color_utils::HSL shift = {-1, 0, 0.5};
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return gfx::ImageSkiaRep(
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkBitmapOperations::CreateHSLShiftedBitmap(icon_rep.sk_bitmap(), shift),
5068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        icon_rep.scale());
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const gfx::ImageSkia icon_;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistruct IconRepresentationInfo {
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Size as a string that will be used to retrieve a representation value from
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // SetIcon function arguments.
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const char* size_string;
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Scale factor for which the represantion should be used.
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ui::ScaleFactor scale;
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst IconRepresentationInfo kIconSizes[] = {{"19", ui::SCALE_FACTOR_100P},
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                             {"38", ui::SCALE_FACTOR_200P}};
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)template <class T>
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool HasValue(const std::map<int, T>& map, int tab_id) {
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return map.find(tab_id) != map.end();
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int ExtensionAction::kDefaultTabId = -1;
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int ExtensionAction::kPageActionIconMaxSize =
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    extension_misc::EXTENSION_ICON_ACTION;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)ExtensionAction::ExtensionAction(const std::string& extension_id,
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 extensions::ActionInfo::Type action_type,
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 const extensions::ActionInfo& manifest_data)
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : extension_id_(extension_id), action_type_(action_type) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Page/script actions are hidden/disabled by default, and browser actions are
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // visible/enabled by default.
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetIsVisible(kDefaultTabId,
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               action_type == extensions::ActionInfo::TYPE_BROWSER);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetTitle(kDefaultTabId, manifest_data.default_title);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetPopupUrl(kDefaultTabId, manifest_data.default_popup_url);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!manifest_data.default_icon.empty()) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    set_default_icon(make_scoped_ptr(new ExtensionIconSet(
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        manifest_data.default_icon)));
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  set_id(manifest_data.id);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ExtensionAction::~ExtensionAction() {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<ExtensionAction> ExtensionAction::CopyForTest() const {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ExtensionAction> copy(
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new ExtensionAction(extension_id_, action_type_,
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          extensions::ActionInfo()));
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  copy->popup_url_ = popup_url_;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  copy->title_ = title_;
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  copy->icon_ = icon_;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  copy->badge_text_ = badge_text_;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  copy->badge_background_color_ = badge_background_color_;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  copy->badge_text_color_ = badge_text_color_;
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  copy->is_visible_ = is_visible_;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  copy->id_ = id_;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (default_icon_)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    copy->default_icon_.reset(new ExtensionIconSet(*default_icon_));
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return copy.Pass();
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ExtensionAction::GetIconSizeForType(
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    extensions::ActionInfo::Type type) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (type) {
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case extensions::ActionInfo::TYPE_BROWSER:
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case extensions::ActionInfo::TYPE_PAGE:
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case extensions::ActionInfo::TYPE_SYSTEM_INDICATOR:
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // TODO(dewittj) Report the actual icon size of the system
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // indicator.
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return extension_misc::EXTENSION_ICON_ACTION;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return 0;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionAction::SetPopupUrl(int tab_id, const GURL& url) {
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We store |url| even if it is empty, rather than removing a URL from the
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // map.  If an extension has a default popup, and removes it for a tab via
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the API, we must remember that there is no popup for that specific tab.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we removed the tab's URL, GetPopupURL would incorrectly return the
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // default URL.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetValue(&popup_url_, tab_id, url);
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ExtensionAction::HasPopup(int tab_id) const {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !GetPopupUrl(tab_id).is_empty();
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GURL ExtensionAction::GetPopupUrl(int tab_id) const {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetValue(&popup_url_, tab_id);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionAction::SetIcon(int tab_id, const gfx::Image& image) {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetValue(&icon_, tab_id, image.AsImageSkia());
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool ExtensionAction::ParseIconFromCanvasDictionary(
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const base::DictionaryValue& dict,
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    gfx::ImageSkia* icon) {
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Try to extract an icon for each known scale.
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (size_t i = 0; i < arraysize(kIconSizes); i++) {
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const base::BinaryValue* image_data;
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    std::string binary_string64;
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    IPC::Message pickle;
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (dict.GetBinary(kIconSizes[i].size_string, &image_data)) {
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      pickle = IPC::Message(image_data->GetBuffer(), image_data->GetSize());
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else if (dict.GetString(kIconSizes[i].size_string, &binary_string64)) {
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      std::string binary_string;
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (!base::Base64Decode(binary_string64, &binary_string))
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        return false;
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      pickle = IPC::Message(binary_string.c_str(), binary_string.length());
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else {
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      continue;
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    PickleIterator iter(pickle);
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    SkBitmap bitmap;
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!IPC::ReadParam(&pickle, &iter, &bitmap))
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return false;
1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CHECK(!bitmap.isNull());
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    float scale = ui::GetScaleForScaleFactor(kIconSizes[i].scale);
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    icon->AddRepresentation(gfx::ImageSkiaRep(bitmap, scale));
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return true;
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::ImageSkia ExtensionAction::GetExplicitlySetIcon(int tab_id) const {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return GetValue(&icon_, tab_id);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool ExtensionAction::SetIsVisible(int tab_id, bool new_visibility) {
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const bool old_visibility = GetValue(&is_visible_, tab_id);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (old_visibility == new_visibility)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetValue(&is_visible_, tab_id, new_visibility);
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionAction::DeclarativeShow(int tab_id) {
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_NE(tab_id, kDefaultTabId);
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ++declarative_show_count_[tab_id];  // Use default initialization to 0.
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ExtensionAction::UndoDeclarativeShow(int tab_id) {
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int& show_count = declarative_show_count_[tab_id];
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK_GT(show_count, 0);
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (--show_count == 0)
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    declarative_show_count_.erase(tab_id);
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ExtensionAction::DeclarativeSetIcon(int tab_id,
2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                         int priority,
2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                         const gfx::Image& icon) {
2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_NE(tab_id, kDefaultTabId);
2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  declarative_icon_[tab_id][priority].push_back(icon);
2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ExtensionAction::UndoDeclarativeSetIcon(int tab_id,
2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                             int priority,
2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                             const gfx::Image& icon) {
2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::vector<gfx::Image>& icons = declarative_icon_[tab_id][priority];
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  for (std::vector<gfx::Image>::iterator it = icons.begin(); it != icons.end();
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       ++it) {
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (it->AsImageSkia().BackedBySameObjectAs(icon.AsImageSkia())) {
2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      icons.erase(it);
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst gfx::ImageSkia ExtensionAction::GetDeclarativeIcon(int tab_id) const {
2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (declarative_icon_.find(tab_id) != declarative_icon_.end() &&
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      !declarative_icon_.find(tab_id)->second.rbegin()->second.empty()) {
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return declarative_icon_.find(tab_id)->second.rbegin()
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ->second.back().AsImageSkia();
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return gfx::ImageSkia();
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionAction::ClearAllValuesForTab(int tab_id) {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  popup_url_.erase(tab_id);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  title_.erase(tab_id);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon_.erase(tab_id);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  badge_text_.erase(tab_id);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  badge_text_color_.erase(tab_id);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  badge_background_color_.erase(tab_id);
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  is_visible_.erase(tab_id);
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(jyasskin): Erase the element from declarative_show_count_
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // when the tab's closed.  There's a race between the
2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // LocationBarController and the ContentRulesRegistry on navigation,
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // which prevents me from cleaning everything up now.
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ExtensionAction::PaintBadge(gfx::Canvas* canvas,
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 const gfx::Rect& bounds,
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 int tab_id) {
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  badge_util::PaintBadge(
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      canvas,
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bounds,
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetBadgeText(tab_id),
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetBadgeTextColor(tab_id),
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetBadgeBackgroundColor(tab_id),
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetIconWidth(tab_id),
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      action_type());
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gfx::ImageSkia ExtensionAction::GetIconWithBadge(
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::ImageSkia& icon,
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int tab_id,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Size& spacing) const {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (tab_id < 0)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return icon;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return gfx::ImageSkia(
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new IconWithBadgeImageSource(icon,
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                   icon.size(),
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   spacing,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   GetBadgeText(tab_id),
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   GetBadgeTextColor(tab_id),
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   GetBadgeBackgroundColor(tab_id),
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   action_type()),
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     icon.size());
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ExtensionAction::HasPopupUrl(int tab_id) const {
286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return HasValue(popup_url_, tab_id);
287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ExtensionAction::HasTitle(int tab_id) const {
290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return HasValue(title_, tab_id);
291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ExtensionAction::HasBadgeText(int tab_id) const {
294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return HasValue(badge_text_, tab_id);
295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ExtensionAction::HasBadgeBackgroundColor(int tab_id) const {
298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return HasValue(badge_background_color_, tab_id);
299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ExtensionAction::HasBadgeTextColor(int tab_id) const {
302a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return HasValue(badge_text_color_, tab_id);
303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
304a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ExtensionAction::HasIsVisible(int tab_id) const {
306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return HasValue(is_visible_, tab_id);
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
308a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
309a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool ExtensionAction::HasIcon(int tab_id) const {
310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return HasValue(icon_, tab_id);
311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Determines which icon would be returned by |GetIcon|, and returns its width.
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ExtensionAction::GetIconWidth(int tab_id) const {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If icon has been set, return its width.
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia icon = GetValue(&icon_, tab_id);
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!icon.isNull())
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return icon.width();
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there is a default icon, the icon width will be set depending on our
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // action type.
321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (default_icon_)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return GetIconSizeForType(action_type());
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If no icon has been set and there is no default icon, we need favicon
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // width.
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ui::ResourceBundle::GetSharedInstance().GetImageNamed(
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          IDR_EXTENSIONS_FAVICON).ToImageSkia()->width();
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
329