OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/common/extensions/extension_action.h" | 5 #include "chrome/common/extensions/extension_action.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "chrome/common/badge_util.h" | 10 #include "chrome/common/badge_util.h" |
11 #include "googleurl/src/gurl.h" | 11 #include "googleurl/src/gurl.h" |
12 #include "grit/ui_resources.h" | 12 #include "grit/ui_resources.h" |
13 #include "third_party/skia/include/core/SkBitmap.h" | 13 #include "third_party/skia/include/core/SkBitmap.h" |
| 14 #include "third_party/skia/include/core/SkCanvas.h" |
| 15 #include "third_party/skia/include/core/SkDevice.h" |
| 16 #include "third_party/skia/include/core/SkPaint.h" |
14 #include "third_party/skia/include/effects/SkGradientShader.h" | 17 #include "third_party/skia/include/effects/SkGradientShader.h" |
| 18 #include "ui/base/animation/animation_delegate.h" |
15 #include "ui/base/resource/resource_bundle.h" | 19 #include "ui/base/resource/resource_bundle.h" |
16 #include "ui/gfx/canvas.h" | 20 #include "ui/gfx/canvas.h" |
17 #include "ui/gfx/rect.h" | 21 #include "ui/gfx/rect.h" |
18 | 22 |
19 namespace { | 23 namespace { |
20 | 24 |
21 // Different platforms need slightly different constants to look good. | 25 // Different platforms need slightly different constants to look good. |
22 #if defined(OS_LINUX) && !defined(TOOLKIT_VIEWS) | 26 #if defined(OS_LINUX) && !defined(TOOLKIT_VIEWS) |
23 const float kTextSize = 9.0; | 27 const float kTextSize = 9.0; |
24 const int kBottomMargin = 0; | 28 const int kBottomMargin = 0; |
(...skipping 18 matching lines...) Expand all Loading... |
43 #endif | 47 #endif |
44 | 48 |
45 const int kBadgeHeight = 11; | 49 const int kBadgeHeight = 11; |
46 const int kMaxTextWidth = 23; | 50 const int kMaxTextWidth = 23; |
47 // The minimum width for center-aligning the badge. | 51 // The minimum width for center-aligning the badge. |
48 const int kCenterAlignThreshold = 20; | 52 const int kCenterAlignThreshold = 20; |
49 | 53 |
50 | 54 |
51 } // namespace | 55 } // namespace |
52 | 56 |
| 57 // Wraps an IconAnimation and implements its ui::AnimationDelegate to erase the |
| 58 // animation from a map when the animation ends or is cancelled, causing itself |
| 59 // and its owned IconAnimation to be deleted. |
| 60 class ExtensionAction::IconAnimationWrapper : public ui::AnimationDelegate { |
| 61 public: |
| 62 IconAnimationWrapper(ExtensionAction* owner, int tab_id) |
| 63 : owner_(owner), |
| 64 tab_id_(tab_id), |
| 65 ALLOW_THIS_IN_INITIALIZER_LIST(animation_(this)) {} |
| 66 |
| 67 virtual ~IconAnimationWrapper() {} |
| 68 |
| 69 IconAnimation* animation() { |
| 70 return &animation_; |
| 71 } |
| 72 |
| 73 private: |
| 74 virtual void AnimationEnded(const ui::Animation* animation) OVERRIDE { |
| 75 Done(); |
| 76 } |
| 77 |
| 78 virtual void AnimationCanceled(const ui::Animation* animation) OVERRIDE { |
| 79 Done(); |
| 80 } |
| 81 |
| 82 void Done() { |
| 83 owner_->icon_animation_.erase(tab_id_); |
| 84 // this will now have been deleted. |
| 85 } |
| 86 |
| 87 ExtensionAction* owner_; |
| 88 int tab_id_; |
| 89 IconAnimation animation_; |
| 90 }; |
| 91 |
53 const int ExtensionAction::kDefaultTabId = -1; | 92 const int ExtensionAction::kDefaultTabId = -1; |
54 | 93 |
| 94 ExtensionAction::IconAnimation::IconAnimation( |
| 95 ui::AnimationDelegate* delegate) |
| 96 // 100ms animation at 50fps (so 5 animation frames in total). |
| 97 : ui::LinearAnimation(100, 50, delegate) {} |
| 98 |
| 99 ExtensionAction::IconAnimation::~IconAnimation() {} |
| 100 |
| 101 const SkBitmap& ExtensionAction::IconAnimation::Apply( |
| 102 const SkBitmap& icon) const { |
| 103 DCHECK_GT(icon.width(), 0); |
| 104 DCHECK_GT(icon.height(), 0); |
| 105 |
| 106 if (!device_.get() || |
| 107 (device_->width() != icon.width()) || |
| 108 (device_->height() != icon.height())) { |
| 109 device_.reset(new SkDevice( |
| 110 SkBitmap::kARGB_8888_Config, icon.width(), icon.height(), true)); |
| 111 } |
| 112 |
| 113 SkCanvas canvas(device_.get()); |
| 114 canvas.clear(SK_ColorWHITE); |
| 115 SkPaint paint; |
| 116 paint.setAlpha(CurrentValueBetween(0, 255)); |
| 117 canvas.drawBitmap(icon, 0, 0, &paint); |
| 118 return device_->accessBitmap(false); |
| 119 } |
| 120 |
| 121 void ExtensionAction::IconAnimation::AddObserver( |
| 122 ExtensionAction::IconAnimation::Observer* observer) { |
| 123 observers_.AddObserver(observer); |
| 124 } |
| 125 |
| 126 void ExtensionAction::IconAnimation::RemoveObserver( |
| 127 ExtensionAction::IconAnimation::Observer* observer) { |
| 128 observers_.RemoveObserver(observer); |
| 129 } |
| 130 |
| 131 void ExtensionAction::IconAnimation::AnimateToState(double state) { |
| 132 FOR_EACH_OBSERVER(Observer, observers_, OnIconChanged(*this)); |
| 133 } |
| 134 |
| 135 ExtensionAction::IconAnimation::ScopedObserver::ScopedObserver( |
| 136 const base::WeakPtr<IconAnimation>& icon_animation, |
| 137 Observer* observer) |
| 138 : icon_animation_(icon_animation), |
| 139 observer_(observer) { |
| 140 if (icon_animation.get()) |
| 141 icon_animation->AddObserver(observer); |
| 142 } |
| 143 |
| 144 ExtensionAction::IconAnimation::ScopedObserver::~ScopedObserver() { |
| 145 if (icon_animation_.get()) |
| 146 icon_animation_->RemoveObserver(observer_); |
| 147 } |
| 148 |
55 ExtensionAction::ExtensionAction(const std::string& extension_id, | 149 ExtensionAction::ExtensionAction(const std::string& extension_id, |
56 Type action_type) | 150 Type action_type) |
57 : extension_id_(extension_id), | 151 : extension_id_(extension_id), |
58 action_type_(action_type) { | 152 action_type_(action_type) { |
59 } | 153 } |
60 | 154 |
61 ExtensionAction::~ExtensionAction() { | 155 ExtensionAction::~ExtensionAction() { |
62 } | 156 } |
63 | 157 |
| 158 scoped_ptr<ExtensionAction> ExtensionAction::CopyForTest() const { |
| 159 scoped_ptr<ExtensionAction> copy( |
| 160 new ExtensionAction(extension_id_, action_type_)); |
| 161 copy->popup_url_ = popup_url_; |
| 162 copy->title_ = title_; |
| 163 copy->icon_ = icon_; |
| 164 copy->icon_index_ = icon_index_; |
| 165 copy->badge_text_ = badge_text_; |
| 166 copy->badge_background_color_ = badge_background_color_; |
| 167 copy->badge_text_color_ = badge_text_color_; |
| 168 copy->visible_ = visible_; |
| 169 copy->icon_animation_ = icon_animation_; |
| 170 copy->default_icon_path_ = default_icon_path_; |
| 171 copy->id_ = id_; |
| 172 copy->icon_paths_ = icon_paths_; |
| 173 return copy.Pass(); |
| 174 } |
| 175 |
64 void ExtensionAction::SetPopupUrl(int tab_id, const GURL& url) { | 176 void ExtensionAction::SetPopupUrl(int tab_id, const GURL& url) { |
65 // We store |url| even if it is empty, rather than removing a URL from the | 177 // We store |url| even if it is empty, rather than removing a URL from the |
66 // map. If an extension has a default popup, and removes it for a tab via | 178 // map. If an extension has a default popup, and removes it for a tab via |
67 // the API, we must remember that there is no popup for that specific tab. | 179 // the API, we must remember that there is no popup for that specific tab. |
68 // If we removed the tab's URL, GetPopupURL would incorrectly return the | 180 // If we removed the tab's URL, GetPopupURL would incorrectly return the |
69 // default URL. | 181 // default URL. |
70 SetValue(&popup_url_, tab_id, url); | 182 SetValue(&popup_url_, tab_id, url); |
71 } | 183 } |
72 | 184 |
73 bool ExtensionAction::HasPopup(int tab_id) const { | 185 bool ExtensionAction::HasPopup(int tab_id) const { |
(...skipping 14 matching lines...) Expand all Loading... |
88 | 200 |
89 void ExtensionAction::SetIconIndex(int tab_id, int index) { | 201 void ExtensionAction::SetIconIndex(int tab_id, int index) { |
90 if (static_cast<size_t>(index) >= icon_paths_.size()) { | 202 if (static_cast<size_t>(index) >= icon_paths_.size()) { |
91 NOTREACHED(); | 203 NOTREACHED(); |
92 return; | 204 return; |
93 } | 205 } |
94 SetValue(&icon_index_, tab_id, index); | 206 SetValue(&icon_index_, tab_id, index); |
95 } | 207 } |
96 | 208 |
97 void ExtensionAction::ClearAllValuesForTab(int tab_id) { | 209 void ExtensionAction::ClearAllValuesForTab(int tab_id) { |
| 210 popup_url_.erase(tab_id); |
98 title_.erase(tab_id); | 211 title_.erase(tab_id); |
99 icon_.erase(tab_id); | 212 icon_.erase(tab_id); |
100 icon_index_.erase(tab_id); | 213 icon_index_.erase(tab_id); |
101 badge_text_.erase(tab_id); | 214 badge_text_.erase(tab_id); |
102 badge_text_color_.erase(tab_id); | 215 badge_text_color_.erase(tab_id); |
103 badge_background_color_.erase(tab_id); | 216 badge_background_color_.erase(tab_id); |
104 visible_.erase(tab_id); | 217 visible_.erase(tab_id); |
105 popup_url_.erase(tab_id); | 218 icon_animation_.erase(tab_id); |
106 } | 219 } |
107 | 220 |
108 void ExtensionAction::PaintBadge(gfx::Canvas* canvas, | 221 void ExtensionAction::PaintBadge(gfx::Canvas* canvas, |
109 const gfx::Rect& bounds, | 222 const gfx::Rect& bounds, |
110 int tab_id) { | 223 int tab_id) { |
111 std::string text = GetBadgeText(tab_id); | 224 std::string text = GetBadgeText(tab_id); |
112 if (text.empty()) | 225 if (text.empty()) |
113 return; | 226 return; |
114 | 227 |
115 SkColor text_color = GetBadgeTextColor(tab_id); | 228 SkColor text_color = GetBadgeTextColor(tab_id); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 // text was too large. | 299 // text was too large. |
187 rect.fLeft += kPadding; | 300 rect.fLeft += kPadding; |
188 rect.fRight -= kPadding; | 301 rect.fRight -= kPadding; |
189 canvas->sk_canvas()->clipRect(rect); | 302 canvas->sk_canvas()->clipRect(rect); |
190 canvas->sk_canvas()->drawText(text.c_str(), text.size(), | 303 canvas->sk_canvas()->drawText(text.c_str(), text.size(), |
191 rect.fLeft + (rect.width() - text_width) / 2, | 304 rect.fLeft + (rect.width() - text_width) / 2, |
192 rect.fTop + kTextSize + kTopTextPadding, | 305 rect.fTop + kTextSize + kTopTextPadding, |
193 *text_paint); | 306 *text_paint); |
194 canvas->Restore(); | 307 canvas->Restore(); |
195 } | 308 } |
| 309 |
| 310 base::WeakPtr<ExtensionAction::IconAnimation> ExtensionAction::GetIconAnimation( |
| 311 int tab_id) const { |
| 312 std::map<int, linked_ptr<IconAnimationWrapper> >::const_iterator it = |
| 313 icon_animation_.find(tab_id); |
| 314 return (it != icon_animation_.end()) ? it->second->animation()->AsWeakPtr() |
| 315 : base::WeakPtr<IconAnimation>(); |
| 316 } |
| 317 |
| 318 void ExtensionAction::RunIconAnimation(int tab_id) { |
| 319 IconAnimationWrapper* icon_animation = |
| 320 new IconAnimationWrapper(this, tab_id); |
| 321 icon_animation_[tab_id] = make_linked_ptr(icon_animation); |
| 322 icon_animation->animation()->Start(); |
| 323 } |
OLD | NEW |