Index: chrome/common/extensions/extension_action.cc |
diff --git a/chrome/common/extensions/extension_action.cc b/chrome/common/extensions/extension_action.cc |
deleted file mode 100644 |
index bab5dfbd563094bd9399a0c64bbb4539d0c1440e..0000000000000000000000000000000000000000 |
--- a/chrome/common/extensions/extension_action.cc |
+++ /dev/null |
@@ -1,524 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/common/extensions/extension_action.h" |
- |
-#include <algorithm> |
- |
-#include "base/bind.h" |
-#include "base/logging.h" |
-#include "base/message_loop.h" |
-#include "chrome/common/badge_util.h" |
-#include "googleurl/src/gurl.h" |
-#include "grit/theme_resources.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/color_utils.h" |
-#include "ui/gfx/image/canvas_image_source.h" |
-#include "ui/gfx/image/image_skia.h" |
-#include "ui/gfx/image/image_skia_source.h" |
-#include "ui/gfx/rect.h" |
-#include "ui/gfx/size.h" |
-#include "ui/gfx/image/image_skia_source.h" |
-#include "ui/gfx/skbitmap_operations.h" |
- |
-namespace { |
- |
-// Different platforms need slightly different constants to look good. |
-#if defined(OS_LINUX) && !defined(TOOLKIT_VIEWS) |
-const float kTextSize = 9.0; |
-const int kBottomMargin = 0; |
-const int kPadding = 2; |
-const int kTopTextPadding = 0; |
-#elif defined(OS_LINUX) && defined(TOOLKIT_VIEWS) |
-const float kTextSize = 8.0; |
-const int kBottomMargin = 5; |
-const int kPadding = 2; |
-const int kTopTextPadding = 1; |
-#elif defined(OS_MACOSX) |
-const float kTextSize = 9.0; |
-const int kBottomMargin = 5; |
-const int kPadding = 2; |
-const int kTopTextPadding = 0; |
-#else |
-const float kTextSize = 10; |
-const int kBottomMargin = 5; |
-const int kPadding = 2; |
-// The padding between the top of the badge and the top of the text. |
-const int kTopTextPadding = -1; |
-#endif |
- |
-const int kBadgeHeight = 11; |
-const int kMaxTextWidth = 23; |
-// The minimum width for center-aligning the badge. |
-const int kCenterAlignThreshold = 20; |
- |
-class GetAttentionImageSource : public gfx::ImageSkiaSource { |
- public: |
- explicit GetAttentionImageSource(const gfx::ImageSkia& icon) |
- : icon_(icon) {} |
- |
- // gfx::ImageSkiaSource overrides: |
- virtual gfx::ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) |
- OVERRIDE { |
- gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale_factor); |
- color_utils::HSL shift = {-1, 0, 0.5}; |
- return gfx::ImageSkiaRep( |
- SkBitmapOperations::CreateHSLShiftedBitmap(icon_rep.sk_bitmap(), shift), |
- icon_rep.scale_factor()); |
- } |
- |
- private: |
- const gfx::ImageSkia icon_; |
-}; |
- |
-} // namespace |
- |
-// TODO(tbarzic): Merge AnimationIconImageSource and IconAnimation together. |
-// Source for painting animated skia image. |
-class AnimatedIconImageSource : public gfx::ImageSkiaSource { |
- public: |
- AnimatedIconImageSource( |
- const gfx::ImageSkia& image, |
- base::WeakPtr<ExtensionAction::IconAnimation> animation) |
- : image_(image), |
- animation_(animation) { |
- } |
- |
- private: |
- virtual ~AnimatedIconImageSource() {} |
- |
- virtual gfx::ImageSkiaRep GetImageForScale(ui::ScaleFactor scale) OVERRIDE { |
- gfx::ImageSkiaRep original_rep = image_.GetRepresentation(scale); |
- if (!animation_) |
- return original_rep; |
- |
- // Original representation's scale factor may be different from scale |
- // factor passed to this method. We want to use the former (since we are |
- // using bitmap for that scale). |
- return gfx::ImageSkiaRep( |
- animation_->Apply(original_rep.sk_bitmap()), |
- original_rep.scale_factor()); |
- } |
- |
- gfx::ImageSkia image_; |
- base::WeakPtr<ExtensionAction::IconAnimation> animation_; |
- |
- DISALLOW_COPY_AND_ASSIGN(AnimatedIconImageSource); |
-}; |
- |
-// CanvasImageSource for creating browser action icon with a badge. |
-class ExtensionAction::IconWithBadgeImageSource |
- : public gfx::CanvasImageSource { |
- public: |
- IconWithBadgeImageSource(const gfx::ImageSkia& icon, |
- const gfx::Size& spacing, |
- const std::string& text, |
- const SkColor& text_color, |
- const SkColor& background_color) |
- : gfx::CanvasImageSource(icon.size(), false), |
- icon_(icon), |
- spacing_(spacing), |
- text_(text), |
- text_color_(text_color), |
- background_color_(background_color) { |
- } |
- |
- virtual ~IconWithBadgeImageSource() {} |
- |
- private: |
- virtual void Draw(gfx::Canvas* canvas) OVERRIDE { |
- canvas->DrawImageInt(icon_, 0, 0, SkPaint()); |
- |
- gfx::Rect bounds(size_.width() + spacing_.width(), |
- size_.height() + spacing_.height()); |
- |
- // Draw a badge on the provided browser action icon's canvas. |
- ExtensionAction::DoPaintBadge(canvas, bounds, text_, text_color_, |
- background_color_, size_.width()); |
- } |
- |
- // Browser action icon image. |
- gfx::ImageSkia icon_; |
- // Extra spacing for badge compared to icon bounds. |
- gfx::Size spacing_; |
- // Text to be displayed on the badge. |
- std::string text_; |
- // Color of badge text. |
- SkColor text_color_; |
- // Color of the badge. |
- SkColor background_color_; |
- |
- DISALLOW_COPY_AND_ASSIGN(IconWithBadgeImageSource); |
-}; |
- |
- |
-const int ExtensionAction::kDefaultTabId = -1; |
-// 100ms animation at 50fps (so 5 animation frames in total). |
-const int kIconFadeInDurationMs = 100; |
-const int kIconFadeInFramesPerSecond = 50; |
- |
-ExtensionAction::IconAnimation::IconAnimation() |
- : ui::LinearAnimation(kIconFadeInDurationMs, kIconFadeInFramesPerSecond, |
- NULL), |
- weak_ptr_factory_(this) {} |
- |
-ExtensionAction::IconAnimation::~IconAnimation() { |
- // Make sure observers don't access *this after its destructor has started. |
- weak_ptr_factory_.InvalidateWeakPtrs(); |
- // In case the animation was destroyed before it finished (likely due to |
- // delays in timer scheduling), make sure it's fully visible. |
- FOR_EACH_OBSERVER(Observer, observers_, OnIconChanged()); |
-} |
- |
-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); |
-} |
- |
-base::WeakPtr<ExtensionAction::IconAnimation> |
-ExtensionAction::IconAnimation::AsWeakPtr() { |
- return weak_ptr_factory_.GetWeakPtr(); |
-} |
- |
-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()); |
-} |
- |
-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), |
- action_type_(action_type), |
- has_changed_(false) { |
-} |
- |
-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->appearance_ = appearance_; |
- 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 |
- // the API, we must remember that there is no popup for that specific tab. |
- // If we removed the tab's URL, GetPopupURL would incorrectly return the |
- // default URL. |
- SetValue(&popup_url_, tab_id, url); |
-} |
- |
-bool ExtensionAction::HasPopup(int tab_id) const { |
- return !GetPopupUrl(tab_id).is_empty(); |
-} |
- |
-GURL ExtensionAction::GetPopupUrl(int tab_id) const { |
- return GetValue(&popup_url_, tab_id); |
-} |
- |
-void ExtensionAction::CacheIcon(const std::string& path, |
- const gfx::Image& icon) { |
- if (!icon.IsEmpty()) |
- path_to_icon_cache_.insert(std::make_pair(path, *icon.ToImageSkia())); |
-} |
- |
-void ExtensionAction::SetIcon(int tab_id, const gfx::Image& image) { |
- SetValue(&icon_, tab_id, image.AsImageSkia()); |
-} |
- |
-gfx::Image ExtensionAction::GetIcon(int tab_id) const { |
- // Check if a specific icon is set for this tab. |
- gfx::ImageSkia icon = GetExplicitlySetIcon(tab_id); |
- if (icon.isNull()) { |
- // Need to find an icon from a path. |
- const std::string* path = NULL; |
- // Check if one of the elements of icon_path() was selected. |
- int icon_index = GetIconIndex(tab_id); |
- if (icon_index >= 0) { |
- path = &icon_paths()->at(icon_index); |
- } else { |
- // Otherwise, use the default icon. |
- path = &default_icon_path(); |
- } |
- |
- std::map<std::string, gfx::ImageSkia>::const_iterator cached_icon = |
- path_to_icon_cache_.find(*path); |
- if (cached_icon != path_to_icon_cache_.end()) { |
- icon = cached_icon->second; |
- } else { |
- icon = *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( |
- IDR_EXTENSIONS_FAVICON); |
- } |
- } |
- |
- if (GetValue(&appearance_, tab_id) == WANTS_ATTENTION) |
- icon = gfx::ImageSkia(new GetAttentionImageSource(icon), icon.size()); |
- |
- return gfx::Image(ApplyIconAnimation(tab_id, icon)); |
-} |
- |
-gfx::ImageSkia ExtensionAction::GetExplicitlySetIcon(int tab_id) const { |
- return GetValue(&icon_, tab_id); |
-} |
- |
-void ExtensionAction::SetIconIndex(int tab_id, int index) { |
- if (static_cast<size_t>(index) >= icon_paths_.size()) { |
- NOTREACHED(); |
- return; |
- } |
- SetValue(&icon_index_, tab_id, index); |
-} |
- |
-bool ExtensionAction::SetAppearance(int tab_id, Appearance new_appearance) { |
- const Appearance old_appearance = GetValue(&appearance_, tab_id); |
- |
- if (old_appearance == new_appearance) |
- return false; |
- |
- SetValue(&appearance_, tab_id, new_appearance); |
- |
- // When showing a badge for the first time on a web page, fade it |
- // in. Other transitions happen instantly. |
- if (old_appearance == INVISIBLE && tab_id != kDefaultTabId) { |
- RunIconAnimation(tab_id); |
- } |
- |
- return true; |
-} |
- |
-void ExtensionAction::ClearAllValuesForTab(int tab_id) { |
- popup_url_.erase(tab_id); |
- title_.erase(tab_id); |
- icon_.erase(tab_id); |
- icon_index_.erase(tab_id); |
- badge_text_.erase(tab_id); |
- badge_text_color_.erase(tab_id); |
- badge_background_color_.erase(tab_id); |
- appearance_.erase(tab_id); |
- icon_animation_.erase(tab_id); |
-} |
- |
-void ExtensionAction::PaintBadge(gfx::Canvas* canvas, |
- const gfx::Rect& bounds, |
- int tab_id) { |
- ExtensionAction::DoPaintBadge( |
- canvas, |
- bounds, |
- GetBadgeText(tab_id), |
- GetBadgeTextColor(tab_id), |
- GetBadgeBackgroundColor(tab_id), |
- GetValue(&icon_, tab_id).size().width()); |
-} |
- |
-gfx::ImageSkia ExtensionAction::GetIconWithBadge( |
- const gfx::ImageSkia& icon, |
- int tab_id, |
- const gfx::Size& spacing) const { |
- if (tab_id < 0) |
- return icon; |
- |
- return gfx::ImageSkia( |
- new IconWithBadgeImageSource(icon, |
- spacing, |
- GetBadgeText(tab_id), |
- GetBadgeTextColor(tab_id), |
- GetBadgeBackgroundColor(tab_id)), |
- icon.size()); |
-} |
- |
-// static |
-void ExtensionAction::DoPaintBadge(gfx::Canvas* canvas, |
- const gfx::Rect& bounds, |
- const std::string& text, |
- const SkColor& text_color_in, |
- const SkColor& background_color_in, |
- int icon_width) { |
- if (text.empty()) |
- return; |
- |
- SkColor text_color = text_color_in; |
- if (SkColorGetA(text_color_in) == 0x00) |
- text_color = SK_ColorWHITE; |
- |
- SkColor background_color = background_color_in; |
- if (SkColorGetA(background_color_in) == 0x00) |
- background_color = SkColorSetARGB(255, 218, 0, 24); |
- |
- canvas->Save(); |
- |
- SkPaint* text_paint = badge_util::GetBadgeTextPaintSingleton(); |
- text_paint->setTextSize(SkFloatToScalar(kTextSize)); |
- text_paint->setColor(text_color); |
- |
- // Calculate text width. We clamp it to a max size. |
- SkScalar sk_text_width = text_paint->measureText(text.c_str(), text.size()); |
- int text_width = std::min(kMaxTextWidth, SkScalarFloor(sk_text_width)); |
- |
- // Calculate badge size. It is clamped to a min width just because it looks |
- // silly if it is too skinny. |
- int badge_width = text_width + kPadding * 2; |
- // Force the pixel width of badge to be either odd (if the icon width is odd) |
- // or even otherwise. If there is a mismatch you get http://crbug.com/26400. |
- if (icon_width != 0 && (badge_width % 2 != icon_width % 2)) |
- badge_width += 1; |
- badge_width = std::max(kBadgeHeight, badge_width); |
- |
- // Paint the badge background color in the right location. It is usually |
- // right-aligned, but it can also be center-aligned if it is large. |
- int rect_height = kBadgeHeight; |
- int rect_y = bounds.bottom() - kBottomMargin - kBadgeHeight; |
- int rect_width = badge_width; |
- int rect_x = (badge_width >= kCenterAlignThreshold) ? |
- (bounds.x() + bounds.width() - badge_width) / 2 : |
- bounds.right() - badge_width; |
- gfx::Rect rect(rect_x, rect_y, rect_width, rect_height); |
- |
- SkPaint rect_paint; |
- rect_paint.setStyle(SkPaint::kFill_Style); |
- rect_paint.setAntiAlias(true); |
- rect_paint.setColor(background_color); |
- canvas->DrawRoundRect(rect, 2, rect_paint); |
- |
- // Overlay the gradient. It is stretchy, so we do this in three parts. |
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
- gfx::ImageSkia* gradient_left = rb.GetImageSkiaNamed( |
- IDR_BROWSER_ACTION_BADGE_LEFT); |
- gfx::ImageSkia* gradient_right = rb.GetImageSkiaNamed( |
- IDR_BROWSER_ACTION_BADGE_RIGHT); |
- gfx::ImageSkia* gradient_center = rb.GetImageSkiaNamed( |
- IDR_BROWSER_ACTION_BADGE_CENTER); |
- |
- canvas->DrawImageInt(*gradient_left, rect.x(), rect.y()); |
- canvas->TileImageInt(*gradient_center, |
- rect.x() + gradient_left->width(), |
- rect.y(), |
- rect.width() - gradient_left->width() - gradient_right->width(), |
- rect.height()); |
- canvas->DrawImageInt(*gradient_right, |
- rect.right() - gradient_right->width(), rect.y()); |
- |
- // Finally, draw the text centered within the badge. We set a clip in case the |
- // text was too large. |
- rect.Inset(kPadding, 0); |
- canvas->ClipRect(rect); |
- canvas->sk_canvas()->drawText( |
- text.c_str(), text.size(), |
- SkFloatToScalar(rect.x() + |
- static_cast<float>(rect.width() - text_width) / 2), |
- SkFloatToScalar(rect.y() + kTextSize + kTopTextPadding), |
- *text_paint); |
- canvas->Restore(); |
-} |
- |
-base::WeakPtr<ExtensionAction::IconAnimation> ExtensionAction::GetIconAnimation( |
- int tab_id) const { |
- std::map<int, base::WeakPtr<IconAnimation> >::iterator it = |
- icon_animation_.find(tab_id); |
- if (it == icon_animation_.end()) |
- return base::WeakPtr<ExtensionAction::IconAnimation>(); |
- if (it->second) |
- return it->second; |
- |
- // Take this opportunity to remove all the NULL IconAnimations from |
- // icon_animation_. |
- icon_animation_.erase(it); |
- for (it = icon_animation_.begin(); it != icon_animation_.end();) { |
- if (it->second) { |
- ++it; |
- } else { |
- // The WeakPtr is null; remove it from the map. |
- icon_animation_.erase(it++); |
- } |
- } |
- return base::WeakPtr<ExtensionAction::IconAnimation>(); |
-} |
- |
-gfx::ImageSkia ExtensionAction::ApplyIconAnimation( |
- int tab_id, |
- const gfx::ImageSkia& icon) const { |
- base::WeakPtr<IconAnimation> animation = GetIconAnimation(tab_id); |
- if (animation == NULL) |
- return icon; |
- |
- return gfx::ImageSkia(new AnimatedIconImageSource(icon, animation), |
- icon.size()); |
-} |
- |
-namespace { |
-// Used to create a Callback owning an IconAnimation. |
-void DestroyIconAnimation(scoped_ptr<ExtensionAction::IconAnimation>) {} |
-} |
-void ExtensionAction::RunIconAnimation(int tab_id) { |
- scoped_ptr<IconAnimation> icon_animation(new IconAnimation()); |
- icon_animation_[tab_id] = icon_animation->AsWeakPtr(); |
- icon_animation->Start(); |
- // After the icon is finished fading in (plus some padding to handle random |
- // timer delays), destroy it. We use a delayed task so that the Animation is |
- // deleted even if it hasn't finished by the time the MessageLoop is |
- // destroyed. |
- MessageLoop::current()->PostDelayedTask( |
- FROM_HERE, |
- base::Bind(&DestroyIconAnimation, base::Passed(icon_animation.Pass())), |
- base::TimeDelta::FromMilliseconds(kIconFadeInDurationMs * 2)); |
-} |