Index: chrome/common/extensions/extension_action.cc |
diff --git a/chrome/common/extensions/extension_action.cc b/chrome/common/extensions/extension_action.cc |
index 9df8905772c436650aa306670ca0f61cf2110778..1e247210e4d4df856467317b18a664c9ebab4f92 100644 |
--- a/chrome/common/extensions/extension_action.cc |
+++ b/chrome/common/extensions/extension_action.cc |
@@ -11,7 +11,11 @@ |
#include "googleurl/src/gurl.h" |
#include "grit/ui_resources.h" |
#include "third_party/skia/include/core/SkBitmap.h" |
+#include "third_party/skia/include/core/SkCanvas.h" |
+#include "third_party/skia/include/core/SkDevice.h" |
+#include "third_party/skia/include/core/SkPaint.h" |
#include "third_party/skia/include/effects/SkGradientShader.h" |
+#include "ui/base/animation/animation_delegate.h" |
#include "ui/base/resource/resource_bundle.h" |
#include "ui/gfx/canvas.h" |
#include "ui/gfx/rect.h" |
@@ -50,8 +54,98 @@ const int kCenterAlignThreshold = 20; |
} // namespace |
+// Wraps an IconAnimation and implements its ui::AnimationDelegate to erase the |
+// animation from a map when the animation ends or is cancelled, causing itself |
+// and its owned IconAnimation to be deleted. |
+class ExtensionAction::IconAnimationWrapper : public ui::AnimationDelegate { |
+ public: |
+ IconAnimationWrapper(ExtensionAction* owner, int tab_id) |
+ : owner_(owner), |
+ tab_id_(tab_id), |
+ ALLOW_THIS_IN_INITIALIZER_LIST(animation_(this)) {} |
+ |
+ virtual ~IconAnimationWrapper() {} |
+ |
+ IconAnimation* animation() { |
+ return &animation_; |
+ } |
+ |
+ private: |
+ virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE { |
+ Done(); |
+ } |
+ |
+ virtual void AnimationCanceled(const ui::Animation* animation) OVERRIDE { |
+ Done(); |
+ } |
+ |
+ void Done() { |
+ owner_->icon_animation_.erase(tab_id_); |
+ // this will now have been deleted. |
+ } |
+ |
+ ExtensionAction* owner_; |
+ int tab_id_; |
+ IconAnimation animation_; |
+}; |
+ |
const int ExtensionAction::kDefaultTabId = -1; |
+ExtensionAction::IconAnimation::IconAnimation( |
+ ui::AnimationDelegate* delegate) |
+ // 100ms animation at 50fps (so 5 animation frames in total). |
+ : ui::LinearAnimation(100, 50, delegate) {} |
+ |
+ExtensionAction::IconAnimation::~IconAnimation() {} |
+ |
+const SkBitmap& ExtensionAction::IconAnimation::Apply( |
+ const SkBitmap& icon) const { |
+ DCHECK_GT(icon.width(), 0); |
+ DCHECK_GT(icon.height(), 0); |
+ |
+ if (!device_.get() || |
+ (device_->width() != icon.width()) || |
+ (device_->height() != icon.height())) { |
+ device_.reset(new SkDevice( |
+ SkBitmap::kARGB_8888_Config, icon.width(), icon.height(), true)); |
+ } |
+ |
+ SkCanvas canvas(device_.get()); |
+ canvas.clear(SK_ColorWHITE); |
+ SkPaint paint; |
+ paint.setAlpha(CurrentValueBetween(0, 255)); |
+ canvas.drawBitmap(icon, 0, 0, &paint); |
+ return device_->accessBitmap(false); |
+} |
+ |
+void ExtensionAction::IconAnimation::AddObserver( |
+ ExtensionAction::IconAnimation::Observer* observer) { |
+ observers_.AddObserver(observer); |
+} |
+ |
+void ExtensionAction::IconAnimation::RemoveObserver( |
+ ExtensionAction::IconAnimation::Observer* observer) { |
+ observers_.RemoveObserver(observer); |
+} |
+ |
+void ExtensionAction::IconAnimation::AnimateToState(double state) { |
+ FOR_EACH_OBSERVER(Observer, observers_, OnIconChanged(*this)); |
+} |
+ |
+ExtensionAction::IconAnimation::ScopedObserver::ScopedObserver( |
+ const base::WeakPtr<IconAnimation>& icon_animation, |
+ Observer* observer) |
+ : icon_animation_(icon_animation), |
+ observer_(observer) { |
+ if (icon_animation.get()) |
+ icon_animation->AddObserver(observer); |
+} |
+ |
+ExtensionAction::IconAnimation::ScopedObserver::~ScopedObserver() { |
+ if (icon_animation_.get()) |
+ icon_animation_->RemoveObserver(observer_); |
+} |
+ |
ExtensionAction::ExtensionAction(const std::string& extension_id, |
Type action_type) |
: extension_id_(extension_id), |
@@ -61,6 +155,24 @@ ExtensionAction::ExtensionAction(const std::string& extension_id, |
ExtensionAction::~ExtensionAction() { |
} |
+scoped_ptr<ExtensionAction> ExtensionAction::CopyForTest() const { |
+ scoped_ptr<ExtensionAction> copy( |
+ new ExtensionAction(extension_id_, action_type_)); |
+ copy->popup_url_ = popup_url_; |
+ copy->title_ = title_; |
+ copy->icon_ = icon_; |
+ copy->icon_index_ = icon_index_; |
+ copy->badge_text_ = badge_text_; |
+ copy->badge_background_color_ = badge_background_color_; |
+ copy->badge_text_color_ = badge_text_color_; |
+ copy->visible_ = visible_; |
+ copy->icon_animation_ = icon_animation_; |
+ copy->default_icon_path_ = default_icon_path_; |
+ copy->id_ = id_; |
+ copy->icon_paths_ = icon_paths_; |
+ return copy.Pass(); |
+} |
+ |
void ExtensionAction::SetPopupUrl(int tab_id, const GURL& url) { |
// We store |url| even if it is empty, rather than removing a URL from the |
// map. If an extension has a default popup, and removes it for a tab via |
@@ -95,6 +207,7 @@ void ExtensionAction::SetIconIndex(int tab_id, int index) { |
} |
void ExtensionAction::ClearAllValuesForTab(int tab_id) { |
+ popup_url_.erase(tab_id); |
title_.erase(tab_id); |
icon_.erase(tab_id); |
icon_index_.erase(tab_id); |
@@ -102,7 +215,7 @@ void ExtensionAction::ClearAllValuesForTab(int tab_id) { |
badge_text_color_.erase(tab_id); |
badge_background_color_.erase(tab_id); |
visible_.erase(tab_id); |
- popup_url_.erase(tab_id); |
+ icon_animation_.erase(tab_id); |
} |
void ExtensionAction::PaintBadge(gfx::Canvas* canvas, |
@@ -193,3 +306,18 @@ void ExtensionAction::PaintBadge(gfx::Canvas* canvas, |
*text_paint); |
canvas->Restore(); |
} |
+ |
+base::WeakPtr<ExtensionAction::IconAnimation> ExtensionAction::GetIconAnimation( |
+ int tab_id) const { |
+ std::map<int, linked_ptr<IconAnimationWrapper> >::const_iterator it = |
+ icon_animation_.find(tab_id); |
+ return (it != icon_animation_.end()) ? it->second->animation()->AsWeakPtr() |
+ : base::WeakPtr<IconAnimation>(); |
+} |
+ |
+void ExtensionAction::RunIconAnimation(int tab_id) { |
+ IconAnimationWrapper* icon_animation = |
+ new IconAnimationWrapper(this, tab_id); |
+ icon_animation_[tab_id] = make_linked_ptr(icon_animation); |
+ icon_animation->animation()->Start(); |
+} |