Chromium Code Reviews| Index: chrome/common/extensions/extension_action.cc |
| diff --git a/chrome/common/extensions/extension_action.cc b/chrome/common/extensions/extension_action.cc |
| index d211778e89ab4230eb2e17c51d7369f991445c5e..4c6d334b2b86935f7273ab82cd5f657c9df2504e 100644 |
| --- a/chrome/common/extensions/extension_action.cc |
| +++ b/chrome/common/extensions/extension_action.cc |
| @@ -20,7 +20,11 @@ |
| #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" |
| @@ -56,16 +60,14 @@ const int kMaxTextWidth = 23; |
| const int kCenterAlignThreshold = 20; |
| -int Width(const gfx::Image& image) { |
| - if (image.IsEmpty()) |
| - return 0; |
| - return image.ToSkBitmap()->width(); |
| +int Width(const gfx::ImageSkia& image) { |
| + return image.size().width(); |
|
Jeffrey Yasskin
2012/08/09 21:39:04
Once this function is a single expression, it's pr
tbarzic
2012/08/10 06:24:08
Done.
|
| } |
| class GetAttentionImageSource : public gfx::ImageSkiaSource { |
| public: |
| - explicit GetAttentionImageSource(const gfx::Image& icon) |
| - : icon_(*icon.ToImageSkia()) {} |
| + explicit GetAttentionImageSource(const gfx::ImageSkia& icon) |
| + : icon_(icon) {} |
| // gfx::ImageSkiaSource overrides: |
| virtual gfx::ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) |
| @@ -115,6 +117,84 @@ class ExtensionAction::IconAnimationWrapper |
| IconAnimation animation_; |
| }; |
| +// TODO(tbarzic): Merge AnimationIconImageSource and IconAnimation together. |
| +// Source for painting animated skia image. |
| +class ExtensionAction::AnimatedIconImageSource : public gfx::ImageSkiaSource { |
| + public: |
| + AnimatedIconImageSource(const gfx::ImageSkia& image, |
| + IconAnimationWrapper* animation) |
| + : image_(image), |
| + animation_(animation->AsWeakPtr()) { |
| + } |
| + |
| + 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 |
|
Jeffrey Yasskin
2012/08/09 21:39:04
It would be nice if CanvasImageSource supported th
tbarzic
2012/08/10 06:24:08
yep.. TODO already added :)
|
| + // factor passed to this method. We want to use the former (since we are |
| + // using bitmap for that scale). |
| + return gfx::ImageSkiaRep( |
| + animation_->animation()->Apply(original_rep.sk_bitmap()), |
| + original_rep.scale_factor()); |
| + } |
| + |
| + gfx::ImageSkia image_; |
| + base::WeakPtr<IconAnimationWrapper> 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; |
| ExtensionAction::IconAnimation::IconAnimation( |
| @@ -219,17 +299,17 @@ GURL ExtensionAction::GetPopupUrl(int tab_id) const { |
| void ExtensionAction::CacheIcon(const std::string& path, |
| const gfx::Image& icon) { |
| if (!icon.IsEmpty()) |
| - path_to_icon_cache_.insert(std::make_pair(path, icon)); |
| + path_to_icon_cache_.insert(std::make_pair(path, *icon.ToImageSkia())); |
| } |
| -void ExtensionAction::SetIcon(int tab_id, const SkBitmap& bitmap) { |
| - SetValue(&icon_, tab_id, gfx::Image(bitmap)); |
| +void ExtensionAction::SetIcon(int tab_id, const gfx::Image& image) { |
| + SetValue(&icon_, tab_id, *image.ToImageSkia()); |
| } |
| gfx::Image ExtensionAction::GetIcon(int tab_id) const { |
| // Check if a specific icon is set for this tab. |
| - gfx::Image icon = GetValue(&icon_, tab_id); |
| - if (icon.IsEmpty()) { |
| + gfx::ImageSkia icon = GetValue(&icon_, tab_id); |
| + if (icon.empty()) { |
| // Need to find an icon from a path. |
| const std::string* path = NULL; |
| // Check if one of the elements of icon_path() was selected. |
| @@ -241,22 +321,20 @@ gfx::Image ExtensionAction::GetIcon(int tab_id) const { |
| path = &default_icon_path(); |
| } |
| - std::map<std::string, gfx::Image>::const_iterator cached_icon = |
| + 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().GetImageNamed( |
| + icon = *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( |
| IDR_EXTENSIONS_FAVICON); |
| } |
| } |
| - if (GetValue(&appearance_, tab_id) == WANTS_ATTENTION) { |
| - icon = gfx::Image(gfx::ImageSkia(new GetAttentionImageSource(icon), |
| - icon.ToImageSkia()->size())); |
| - } |
| + if (GetValue(&appearance_, tab_id) == WANTS_ATTENTION) |
| + icon = gfx::ImageSkia(new GetAttentionImageSource(icon), icon.size()); |
| - return ApplyIconAnimation(tab_id, icon); |
| + return gfx::Image(ApplyIconAnimation(tab_id, icon)); |
| } |
| void ExtensionAction::SetIconIndex(int tab_id, int index) { |
| @@ -299,18 +377,46 @@ void ExtensionAction::ClearAllValuesForTab(int tab_id) { |
| void ExtensionAction::PaintBadge(gfx::Canvas* canvas, |
| const gfx::Rect& bounds, |
| int tab_id) { |
| - std::string text = GetBadgeText(tab_id); |
| + ExtensionAction::DoPaintBadge( |
| + canvas, |
| + bounds, |
| + GetBadgeText(tab_id), |
| + GetBadgeTextColor(tab_id), |
| + GetBadgeBackgroundColor(tab_id), |
| + Width(GetValue(&icon_, tab_id))); |
| +} |
| + |
| +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 = GetBadgeTextColor(tab_id); |
| - SkColor background_color = GetBadgeBackgroundColor(tab_id); |
| + SkColor text_color = (SkColorGetA(text_color_in) == 0x00) ? |
|
Jeffrey Yasskin
2012/08/09 21:39:04
Interesting. I would probably have kept the if sta
tbarzic
2012/08/10 06:24:08
Done.
|
| + SK_ColorWHITE : text_color_in; |
| - if (SkColorGetA(text_color) == 0x00) |
| - text_color = SK_ColorWHITE; |
| - |
| - if (SkColorGetA(background_color) == 0x00) |
| - background_color = SkColorSetARGB(255, 218, 0, 24); // Default badge color. |
| + SkColor background_color = (SkColorGetA(background_color_in) == 0x00) ? |
| + SkColorSetARGB(255, 218, 0, 24) : background_color_in; |
| canvas->Save(); |
| @@ -319,14 +425,12 @@ void ExtensionAction::PaintBadge(gfx::Canvas* canvas, |
| text_paint->setColor(text_color); |
| // Calculate text width. We clamp it to a max size. |
| - SkScalar text_width = text_paint->measureText(text.c_str(), text.size()); |
| - text_width = SkIntToScalar( |
| - std::min(kMaxTextWidth, SkScalarFloor(text_width))); |
| + 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 = SkScalarFloor(text_width) + kPadding * 2; |
| - int icon_width = Width(GetValue(&icon_, tab_id)); |
| + 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)) |
| @@ -335,52 +439,45 @@ void ExtensionAction::PaintBadge(gfx::Canvas* canvas, |
| // 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. |
| - SkRect rect; |
| - rect.fBottom = SkIntToScalar(bounds.bottom() - kBottomMargin); |
| - rect.fTop = rect.fBottom - SkIntToScalar(kBadgeHeight); |
| - if (badge_width >= kCenterAlignThreshold) { |
| - rect.fLeft = SkIntToScalar( |
| - SkScalarFloor(SkIntToScalar(bounds.x()) + |
| - SkIntToScalar(bounds.width()) / 2 - |
| - SkIntToScalar(badge_width) / 2)); |
| - rect.fRight = rect.fLeft + SkIntToScalar(badge_width); |
| - } else { |
| - rect.fRight = SkIntToScalar(bounds.right()); |
| - rect.fLeft = rect.fRight - badge_width; |
| - } |
| + 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()) / 2 - 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->sk_canvas()->drawRoundRect(rect, SkIntToScalar(2), |
| - SkIntToScalar(2), rect_paint); |
| + 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(); |
| - SkBitmap* gradient_left = rb.GetBitmapNamed(IDR_BROWSER_ACTION_BADGE_LEFT); |
| - SkBitmap* gradient_right = rb.GetBitmapNamed(IDR_BROWSER_ACTION_BADGE_RIGHT); |
| - SkBitmap* gradient_center = rb.GetBitmapNamed( |
| + 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->sk_canvas()->drawBitmap(*gradient_left, rect.fLeft, rect.fTop); |
| + canvas->DrawImageInt(*gradient_left, rect.x(), rect.y()); |
| canvas->TileImageInt(*gradient_center, |
| - SkScalarFloor(rect.fLeft) + gradient_left->width(), |
| - SkScalarFloor(rect.fTop), |
| - SkScalarFloor(rect.width()) - gradient_left->width() - |
| - gradient_right->width(), |
| - SkScalarFloor(rect.height())); |
| - canvas->sk_canvas()->drawBitmap(*gradient_right, |
| - rect.fRight - SkIntToScalar(gradient_right->width()), rect.fTop); |
| + 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.fLeft += kPadding; |
| - rect.fRight -= kPadding; |
| - canvas->sk_canvas()->clipRect(rect); |
| + rect.Inset(kPadding, 0); |
| + canvas->ClipRect(rect); |
| canvas->sk_canvas()->drawText(text.c_str(), text.size(), |
| - rect.fLeft + (rect.width() - text_width) / 2, |
| - rect.fTop + kTextSize + kTopTextPadding, |
| + rect.x() + (rect.width() - text_width) / 2, |
| + rect.y() + kTextSize + kTopTextPadding, |
| *text_paint); |
| canvas->Restore(); |
| } |
| @@ -415,12 +512,15 @@ base::WeakPtr<ExtensionAction::IconAnimation> ExtensionAction::GetIconAnimation( |
| : base::WeakPtr<IconAnimation>(); |
| } |
| -gfx::Image ExtensionAction::ApplyIconAnimation(int tab_id, |
| - const gfx::Image& orig) const { |
| - IconAnimationWrapper* wrapper = GetIconAnimationWrapper(tab_id); |
| - if (wrapper == NULL) |
| - return orig; |
| - return gfx::Image(wrapper->animation()->Apply(*orig.ToSkBitmap())); |
| +gfx::ImageSkia ExtensionAction::ApplyIconAnimation( |
| + int tab_id, |
| + const gfx::ImageSkia& icon) const { |
| + IconAnimationWrapper* animation_wrapper = GetIconAnimationWrapper(tab_id); |
| + if (animation_wrapper == NULL) |
| + return icon; |
| + |
| + return gfx::ImageSkia(new AnimatedIconImageSource(icon, animation_wrapper), |
| + icon.size()); |
| } |
| void ExtensionAction::RunIconAnimation(int tab_id) { |