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/bind.h" | 9 #include "base/bind.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
12 #include "chrome/common/badge_util.h" | 12 #include "chrome/common/badge_util.h" |
13 #include "chrome/common/extensions/extension_constants.h" | |
13 #include "googleurl/src/gurl.h" | 14 #include "googleurl/src/gurl.h" |
14 #include "grit/theme_resources.h" | 15 #include "grit/theme_resources.h" |
15 #include "grit/ui_resources.h" | 16 #include "grit/ui_resources.h" |
16 #include "third_party/skia/include/core/SkBitmap.h" | 17 #include "third_party/skia/include/core/SkBitmap.h" |
17 #include "third_party/skia/include/core/SkCanvas.h" | 18 #include "third_party/skia/include/core/SkCanvas.h" |
18 #include "third_party/skia/include/core/SkDevice.h" | 19 #include "third_party/skia/include/core/SkDevice.h" |
19 #include "third_party/skia/include/core/SkPaint.h" | 20 #include "third_party/skia/include/core/SkPaint.h" |
20 #include "third_party/skia/include/effects/SkGradientShader.h" | 21 #include "third_party/skia/include/effects/SkGradientShader.h" |
21 #include "ui/base/animation/animation_delegate.h" | 22 #include "ui/base/animation/animation_delegate.h" |
22 #include "ui/base/resource/resource_bundle.h" | 23 #include "ui/base/resource/resource_bundle.h" |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
54 const int kPadding = 2; | 55 const int kPadding = 2; |
55 // The padding between the top of the badge and the top of the text. | 56 // The padding between the top of the badge and the top of the text. |
56 const int kTopTextPadding = -1; | 57 const int kTopTextPadding = -1; |
57 #endif | 58 #endif |
58 | 59 |
59 const int kBadgeHeight = 11; | 60 const int kBadgeHeight = 11; |
60 const int kMaxTextWidth = 23; | 61 const int kMaxTextWidth = 23; |
61 // The minimum width for center-aligning the badge. | 62 // The minimum width for center-aligning the badge. |
62 const int kCenterAlignThreshold = 20; | 63 const int kCenterAlignThreshold = 20; |
63 | 64 |
65 void CopyExtensionIconSet(const ExtensionIconSet* from, ExtensionIconSet* to) { | |
Jeffrey Yasskin
2012/09/13 00:23:36
If we want this function, I suspect ExtensionIconS
tbarzic
2012/09/13 02:01:01
I don't think we want this functionality in produc
| |
66 for (ExtensionIconSet::IconMap::const_iterator iter = from->map().begin(); | |
67 iter != from->map().end(); | |
68 ++iter) { | |
69 to->Add(iter->first, iter->second); | |
70 } | |
71 } | |
72 | |
73 int GetDesiredIconSizeForActionType(ExtensionAction::Type type) { | |
74 switch (type) { | |
75 case ExtensionAction::TYPE_BROWSER: | |
76 case ExtensionAction::TYPE_PAGE: | |
77 return extension_misc::EXTENSION_ICON_ACTION; | |
78 case ExtensionAction::TYPE_SCRIPT_BADGE: | |
79 return extension_misc::EXTENSION_ICON_BITTY; | |
80 default: | |
81 NOTREACHED(); | |
82 return 0; | |
83 } | |
84 } | |
85 | |
86 gfx::ImageSkia GetIconFromIconSet(const ExtensionIconSet* icon_set, | |
Jeffrey Yasskin
2012/09/13 00:23:36
This function doesn't seem to pull its weight. I'd
tbarzic
2012/09/13 02:01:01
Done.
| |
87 ExtensionIconFactoryDelegate* icon_factory, | |
88 ExtensionAction::Type type) { | |
89 if (!icon_set || !icon_factory) | |
90 return gfx::ImageSkia(); | |
91 | |
92 return icon_factory->GetIcon(icon_set, GetDesiredIconSizeForActionType(type)); | |
93 } | |
94 | |
64 class GetAttentionImageSource : public gfx::ImageSkiaSource { | 95 class GetAttentionImageSource : public gfx::ImageSkiaSource { |
65 public: | 96 public: |
66 explicit GetAttentionImageSource(const gfx::ImageSkia& icon) | 97 explicit GetAttentionImageSource(const gfx::ImageSkia& icon) |
67 : icon_(icon) {} | 98 : icon_(icon) {} |
68 | 99 |
69 // gfx::ImageSkiaSource overrides: | 100 // gfx::ImageSkiaSource overrides: |
70 virtual gfx::ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) | 101 virtual gfx::ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) |
71 OVERRIDE { | 102 OVERRIDE { |
72 gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale_factor); | 103 gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale_factor); |
73 color_utils::HSL shift = {-1, 0, 0.5}; | 104 color_utils::HSL shift = {-1, 0, 0.5}; |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
247 new ExtensionAction(extension_id_, action_type_)); | 278 new ExtensionAction(extension_id_, action_type_)); |
248 copy->popup_url_ = popup_url_; | 279 copy->popup_url_ = popup_url_; |
249 copy->title_ = title_; | 280 copy->title_ = title_; |
250 copy->icon_ = icon_; | 281 copy->icon_ = icon_; |
251 copy->icon_index_ = icon_index_; | 282 copy->icon_index_ = icon_index_; |
252 copy->badge_text_ = badge_text_; | 283 copy->badge_text_ = badge_text_; |
253 copy->badge_background_color_ = badge_background_color_; | 284 copy->badge_background_color_ = badge_background_color_; |
254 copy->badge_text_color_ = badge_text_color_; | 285 copy->badge_text_color_ = badge_text_color_; |
255 copy->appearance_ = appearance_; | 286 copy->appearance_ = appearance_; |
256 copy->icon_animation_ = icon_animation_; | 287 copy->icon_animation_ = icon_animation_; |
257 copy->default_icon_path_ = default_icon_path_; | |
258 copy->id_ = id_; | 288 copy->id_ = id_; |
259 copy->icon_paths_ = icon_paths_; | 289 |
290 if (default_icon_.get()) { | |
291 scoped_ptr<ExtensionIconSet> default_icon(new ExtensionIconSet()); | |
292 CopyExtensionIconSet(default_icon_.get(), default_icon.get()); | |
293 copy->default_icon_ = default_icon.Pass(); | |
294 } | |
295 | |
296 for (size_t i = 0; i < page_action_icons_.size(); i++) { | |
297 scoped_ptr<ExtensionIconSet> page_action_icon(new ExtensionIconSet()); | |
298 CopyExtensionIconSet(page_action_icons_[i], page_action_icon.get()); | |
299 copy->AddPageActionIcon(page_action_icon.Pass()); | |
300 } | |
301 | |
260 return copy.Pass(); | 302 return copy.Pass(); |
261 } | 303 } |
262 | 304 |
305 void ExtensionAction::AddPageActionIcon(scoped_ptr<ExtensionIconSet> icon_set) { | |
306 page_action_icons_.push_back(icon_set.release()); | |
307 } | |
308 | |
309 bool ExtensionAction::IsValidIconIndex(int index) const { | |
310 return index >= 0 && (static_cast<size_t>(index) < page_action_icons_.size()); | |
311 } | |
312 | |
263 void ExtensionAction::SetPopupUrl(int tab_id, const GURL& url) { | 313 void ExtensionAction::SetPopupUrl(int tab_id, const GURL& url) { |
264 // We store |url| even if it is empty, rather than removing a URL from the | 314 // We store |url| even if it is empty, rather than removing a URL from the |
265 // map. If an extension has a default popup, and removes it for a tab via | 315 // map. If an extension has a default popup, and removes it for a tab via |
266 // the API, we must remember that there is no popup for that specific tab. | 316 // the API, we must remember that there is no popup for that specific tab. |
267 // If we removed the tab's URL, GetPopupURL would incorrectly return the | 317 // If we removed the tab's URL, GetPopupURL would incorrectly return the |
268 // default URL. | 318 // default URL. |
269 SetValue(&popup_url_, tab_id, url); | 319 SetValue(&popup_url_, tab_id, url); |
270 } | 320 } |
271 | 321 |
272 bool ExtensionAction::HasPopup(int tab_id) const { | 322 bool ExtensionAction::HasPopup(int tab_id) const { |
273 return !GetPopupUrl(tab_id).is_empty(); | 323 return !GetPopupUrl(tab_id).is_empty(); |
274 } | 324 } |
275 | 325 |
276 GURL ExtensionAction::GetPopupUrl(int tab_id) const { | 326 GURL ExtensionAction::GetPopupUrl(int tab_id) const { |
277 return GetValue(&popup_url_, tab_id); | 327 return GetValue(&popup_url_, tab_id); |
278 } | 328 } |
279 | 329 |
280 void ExtensionAction::CacheIcon(const std::string& path, | |
281 const gfx::Image& icon) { | |
282 if (!icon.IsEmpty()) | |
283 path_to_icon_cache_.insert(std::make_pair(path, *icon.ToImageSkia())); | |
284 } | |
285 | |
286 void ExtensionAction::SetIcon(int tab_id, const gfx::Image& image) { | 330 void ExtensionAction::SetIcon(int tab_id, const gfx::Image& image) { |
287 SetValue(&icon_, tab_id, image.AsImageSkia()); | 331 SetValue(&icon_, tab_id, image.AsImageSkia()); |
288 } | 332 } |
289 | 333 |
290 gfx::Image ExtensionAction::GetIcon(int tab_id) const { | 334 gfx::Image ExtensionAction::GetIcon( |
335 int tab_id, | |
336 ExtensionIconFactoryDelegate* icon_factory) const { | |
291 // Check if a specific icon is set for this tab. | 337 // Check if a specific icon is set for this tab. |
292 gfx::ImageSkia icon = GetExplicitlySetIcon(tab_id); | 338 gfx::ImageSkia icon = GetExplicitlySetIcon(tab_id); |
293 if (icon.isNull()) { | 339 if (icon.isNull()) { |
294 // Need to find an icon from a path. | |
295 const std::string* path = NULL; | |
296 // Check if one of the elements of icon_path() was selected. | 340 // Check if one of the elements of icon_path() was selected. |
297 int icon_index = GetIconIndex(tab_id); | 341 int icon_index = GetIconIndex(tab_id); |
342 const ExtensionIconSet* icon_set = NULL; | |
298 if (icon_index >= 0) { | 343 if (icon_index >= 0) { |
299 path = &icon_paths()->at(icon_index); | 344 icon_set = page_action_icons_[icon_index]; |
300 } else { | 345 } else { |
301 // Otherwise, use the default icon. | 346 icon_set = default_icon_.get(); |
302 path = &default_icon_path(); | |
303 } | 347 } |
304 | 348 |
305 std::map<std::string, gfx::ImageSkia>::const_iterator cached_icon = | 349 icon = GetIconFromIconSet(icon_set, icon_factory, action_type()); |
306 path_to_icon_cache_.find(*path); | 350 |
307 if (cached_icon != path_to_icon_cache_.end()) { | 351 // Extension favicon is our last resort. |
308 icon = cached_icon->second; | 352 if (icon.isNull()) { |
309 } else { | |
310 icon = *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( | 353 icon = *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( |
311 IDR_EXTENSIONS_FAVICON); | 354 IDR_EXTENSIONS_FAVICON); |
312 } | 355 } |
313 } | 356 } |
314 | 357 |
315 if (GetValue(&appearance_, tab_id) == WANTS_ATTENTION) | 358 if (GetValue(&appearance_, tab_id) == WANTS_ATTENTION) |
316 icon = gfx::ImageSkia(new GetAttentionImageSource(icon), icon.size()); | 359 icon = gfx::ImageSkia(new GetAttentionImageSource(icon), icon.size()); |
317 | 360 |
318 return gfx::Image(ApplyIconAnimation(tab_id, icon)); | 361 return gfx::Image(ApplyIconAnimation(tab_id, icon)); |
319 } | 362 } |
320 | 363 |
321 gfx::ImageSkia ExtensionAction::GetExplicitlySetIcon(int tab_id) const { | 364 gfx::ImageSkia ExtensionAction::GetExplicitlySetIcon(int tab_id) const { |
322 return GetValue(&icon_, tab_id); | 365 return GetValue(&icon_, tab_id); |
323 } | 366 } |
324 | 367 |
325 void ExtensionAction::SetIconIndex(int tab_id, int index) { | 368 void ExtensionAction::SetIconIndex(int tab_id, int index) { |
326 if (static_cast<size_t>(index) >= icon_paths_.size()) { | 369 if (static_cast<size_t>(index) >= page_action_icons_.size()) { |
327 NOTREACHED(); | 370 NOTREACHED(); |
328 return; | 371 return; |
329 } | 372 } |
330 SetValue(&icon_index_, tab_id, index); | 373 SetValue(&icon_index_, tab_id, index); |
331 } | 374 } |
332 | 375 |
333 bool ExtensionAction::SetAppearance(int tab_id, Appearance new_appearance) { | 376 bool ExtensionAction::SetAppearance(int tab_id, Appearance new_appearance) { |
334 const Appearance old_appearance = GetValue(&appearance_, tab_id); | 377 const Appearance old_appearance = GetValue(&appearance_, tab_id); |
335 | 378 |
336 if (old_appearance == new_appearance) | 379 if (old_appearance == new_appearance) |
337 return false; | 380 return false; |
338 | 381 |
382 // Remeber icon width so it can be used for badge painting. | |
Jeffrey Yasskin
2012/09/13 00:23:36
This doesn't look like the width being rembered.
tbarzic
2012/09/13 02:01:01
Done.
| |
339 SetValue(&appearance_, tab_id, new_appearance); | 383 SetValue(&appearance_, tab_id, new_appearance); |
340 | 384 |
341 // When showing a badge for the first time on a web page, fade it | 385 // When showing a badge for the first time on a web page, fade it |
342 // in. Other transitions happen instantly. | 386 // in. Other transitions happen instantly. |
343 if (old_appearance == INVISIBLE && tab_id != kDefaultTabId) { | 387 if (old_appearance == INVISIBLE && tab_id != kDefaultTabId) { |
344 RunIconAnimation(tab_id); | 388 RunIconAnimation(tab_id); |
345 } | 389 } |
346 | 390 |
347 return true; | 391 return true; |
348 } | 392 } |
(...skipping 12 matching lines...) Expand all Loading... | |
361 | 405 |
362 void ExtensionAction::PaintBadge(gfx::Canvas* canvas, | 406 void ExtensionAction::PaintBadge(gfx::Canvas* canvas, |
363 const gfx::Rect& bounds, | 407 const gfx::Rect& bounds, |
364 int tab_id) { | 408 int tab_id) { |
365 ExtensionAction::DoPaintBadge( | 409 ExtensionAction::DoPaintBadge( |
366 canvas, | 410 canvas, |
367 bounds, | 411 bounds, |
368 GetBadgeText(tab_id), | 412 GetBadgeText(tab_id), |
369 GetBadgeTextColor(tab_id), | 413 GetBadgeTextColor(tab_id), |
370 GetBadgeBackgroundColor(tab_id), | 414 GetBadgeBackgroundColor(tab_id), |
371 GetValue(&icon_, tab_id).size().width()); | 415 GetIconWidth(tab_id)); |
372 } | 416 } |
373 | 417 |
374 gfx::ImageSkia ExtensionAction::GetIconWithBadge( | 418 gfx::ImageSkia ExtensionAction::GetIconWithBadge( |
375 const gfx::ImageSkia& icon, | 419 const gfx::ImageSkia& icon, |
376 int tab_id, | 420 int tab_id, |
377 const gfx::Size& spacing) const { | 421 const gfx::Size& spacing) const { |
378 if (tab_id < 0) | 422 if (tab_id < 0) |
379 return icon; | 423 return icon; |
380 | 424 |
381 return gfx::ImageSkia( | 425 return gfx::ImageSkia( |
382 new IconWithBadgeImageSource(icon, | 426 new IconWithBadgeImageSource(icon, |
383 spacing, | 427 spacing, |
384 GetBadgeText(tab_id), | 428 GetBadgeText(tab_id), |
385 GetBadgeTextColor(tab_id), | 429 GetBadgeTextColor(tab_id), |
386 GetBadgeBackgroundColor(tab_id)), | 430 GetBadgeBackgroundColor(tab_id)), |
387 icon.size()); | 431 icon.size()); |
388 } | 432 } |
389 | 433 |
434 // Determines which icon would be returned by |GetIcon|, and returns its width. | |
435 int ExtensionAction:: GetIconWidth(int tab_id) const { | |
Jeffrey Yasskin
2012/09/13 00:23:36
No space between :: and the method name.
tbarzic
2012/09/13 02:01:01
Done.
| |
436 // If icon has been set, return its width. | |
437 gfx::ImageSkia icon = GetValue(&icon_, tab_id); | |
438 if (!icon.isNull()) | |
439 return icon.width(); | |
440 // If page action icon has been set, or there is a default icon, the icon | |
441 // the icon width will be set depending on our action type. | |
Jeffrey Yasskin
2012/09/13 00:23:36
typo: "the icon the icon width"
tbarzic
2012/09/13 02:01:01
Done.
| |
442 int icon_index = GetIconIndex(tab_id); | |
443 if (icon_index >= 0 || default_icon_.get()) | |
444 return GetDesiredIconSizeForActionType(action_type()); | |
445 | |
446 // If no icon has been set and there is no default icon, we need favicon | |
447 // width. | |
448 return ui::ResourceBundle::GetSharedInstance().GetImageNamed( | |
449 IDR_EXTENSIONS_FAVICON).ToImageSkia()->width(); | |
450 } | |
451 | |
390 // static | 452 // static |
391 void ExtensionAction::DoPaintBadge(gfx::Canvas* canvas, | 453 void ExtensionAction::DoPaintBadge(gfx::Canvas* canvas, |
392 const gfx::Rect& bounds, | 454 const gfx::Rect& bounds, |
393 const std::string& text, | 455 const std::string& text, |
394 const SkColor& text_color_in, | 456 const SkColor& text_color_in, |
395 const SkColor& background_color_in, | 457 const SkColor& background_color_in, |
396 int icon_width) { | 458 int icon_width) { |
397 if (text.empty()) | 459 if (text.empty()) |
398 return; | 460 return; |
399 | 461 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
515 icon_animation->Start(); | 577 icon_animation->Start(); |
516 // After the icon is finished fading in (plus some padding to handle random | 578 // After the icon is finished fading in (plus some padding to handle random |
517 // timer delays), destroy it. We use a delayed task so that the Animation is | 579 // timer delays), destroy it. We use a delayed task so that the Animation is |
518 // deleted even if it hasn't finished by the time the MessageLoop is | 580 // deleted even if it hasn't finished by the time the MessageLoop is |
519 // destroyed. | 581 // destroyed. |
520 MessageLoop::current()->PostDelayedTask( | 582 MessageLoop::current()->PostDelayedTask( |
521 FROM_HERE, | 583 FROM_HERE, |
522 base::Bind(&DestroyIconAnimation, base::Passed(icon_animation.Pass())), | 584 base::Bind(&DestroyIconAnimation, base::Passed(icon_animation.Pass())), |
523 base::TimeDelta::FromMilliseconds(kIconFadeInDurationMs * 2)); | 585 base::TimeDelta::FromMilliseconds(kIconFadeInDurationMs * 2)); |
524 } | 586 } |
OLD | NEW |