Index: chrome/browser/gtk/tabs/tab_renderer_gtk.cc |
=================================================================== |
--- chrome/browser/gtk/tabs/tab_renderer_gtk.cc (revision 16331) |
+++ chrome/browser/gtk/tabs/tab_renderer_gtk.cc (working copy) |
@@ -43,6 +43,8 @@ |
const int kCloseButtonVertFuzz = 0; |
const int kCloseButtonHorzFuzz = 5; |
+SkBitmap* crashed_fav_icon = NULL; |
+ |
TabRendererGtk::LoadingAnimation::Data loading_animation_data; |
// Loads the loading animation images and data. |
@@ -126,6 +128,45 @@ |
} |
//////////////////////////////////////////////////////////////////////////////// |
+// FaviconCrashAnimation |
+// |
+// A custom animation subclass to manage the favicon crash animation. |
+class TabRendererGtk::FavIconCrashAnimation : public Animation, |
+ public AnimationDelegate { |
+ public: |
+ explicit FavIconCrashAnimation(TabRendererGtk* target) |
+ : ALLOW_THIS_IN_INITIALIZER_LIST(Animation(1000, 25, this)), |
+ target_(target) { |
+ } |
+ virtual ~FavIconCrashAnimation() {} |
+ |
+ // Animation overrides: |
+ virtual void AnimateToState(double state) { |
+ const double kHidingOffset = 27; |
+ |
+ if (state < .5) { |
+ target_->SetFavIconHidingOffset( |
+ static_cast<int>(floor(kHidingOffset * 2.0 * state))); |
+ } else { |
+ target_->DisplayCrashedFavIcon(); |
+ target_->SetFavIconHidingOffset( |
+ static_cast<int>( |
+ floor(kHidingOffset - ((state - .5) * 2.0 * kHidingOffset)))); |
+ } |
+ } |
+ |
+ // AnimationDelegate overrides: |
+ virtual void AnimationCanceled(const Animation* animation) { |
+ target_->SetFavIconHidingOffset(0); |
+ } |
+ |
+ private: |
+ TabRendererGtk* target_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(FavIconCrashAnimation); |
+}; |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
// TabRendererGtk, public: |
TabRendererGtk::TabRendererGtk() |
@@ -172,6 +213,16 @@ |
void TabRendererGtk::UpdateFromModel() { |
// Force a layout, since the tab may have grown a favicon. |
Layout(); |
+ SchedulePaint(); |
+ |
+ if (data_.crashed) { |
+ if (!should_display_crashed_favicon_ && !IsPerformingCrashAnimation()) |
+ StartCrashAnimation(); |
+ } else { |
+ if (IsPerformingCrashAnimation()) |
+ StopCrashAnimation(); |
+ ResetCrashedFavIcon(); |
+ } |
} |
bool TabRendererGtk::IsSelected() const { |
@@ -290,6 +341,36 @@ |
//////////////////////////////////////////////////////////////////////////////// |
// TabRendererGtk, private: |
+void TabRendererGtk::StartCrashAnimation() { |
+ if (!crash_animation_.get()) |
+ crash_animation_.reset(new FavIconCrashAnimation(this)); |
+ crash_animation_->Reset(); |
+ crash_animation_->Start(); |
+} |
+ |
+void TabRendererGtk::StopCrashAnimation() { |
+ if (!crash_animation_.get()) |
+ return; |
+ crash_animation_->Stop(); |
+} |
+ |
+bool TabRendererGtk::IsPerformingCrashAnimation() const { |
+ return crash_animation_.get() && crash_animation_->IsAnimating(); |
+} |
+ |
+void TabRendererGtk::SetFavIconHidingOffset(int offset) { |
+ fav_icon_hiding_offset_ = offset; |
+ SchedulePaint(); |
+} |
+ |
+void TabRendererGtk::DisplayCrashedFavIcon() { |
+ should_display_crashed_favicon_ = true; |
+} |
+ |
+void TabRendererGtk::ResetCrashedFavIcon() { |
+ should_display_crashed_favicon_ = false; |
+} |
+ |
void TabRendererGtk::Paint(GdkEventExpose* event) { |
gfx::CanvasPaint canvas(event, false); |
if (canvas.isEmpty()) |
@@ -314,9 +395,31 @@ |
if (show_icon) { |
if (loading_animation_.animation_state() != ANIMATION_NONE) { |
PaintLoadingAnimation(&canvas); |
- } else if (!data_.favicon.isNull()) { |
- canvas.DrawBitmapInt(data_.favicon, favicon_bounds_.x(), |
- favicon_bounds_.y() + fav_icon_hiding_offset_); |
+ } else { |
+ canvas.save(); |
+ canvas.ClipRectInt(0, 0, width(), height() - kFavIconTitleSpacing); |
+ if (should_display_crashed_favicon_) { |
+ canvas.DrawBitmapInt(*crashed_fav_icon, 0, 0, |
+ crashed_fav_icon->width(), |
+ crashed_fav_icon->height(), |
+ favicon_bounds_.x(), |
+ favicon_bounds_.y() + fav_icon_hiding_offset_, |
+ kFavIconSize, kFavIconSize, |
+ true); |
+ } else { |
+ if (!data_.favicon.isNull()) { |
+ // TODO(pkasting): Use code in tab_icon_view.cc:PaintIcon() (or switch |
+ // to using that class to render the favicon). |
+ canvas.DrawBitmapInt(data_.favicon, 0, 0, |
+ data_.favicon.width(), |
+ data_.favicon.height(), |
+ favicon_bounds_.x(), |
+ favicon_bounds_.y() + fav_icon_hiding_offset_, |
+ kFavIconSize, kFavIconSize, |
+ true); |
+ } |
+ } |
+ canvas.restore(); |
} |
} |
@@ -607,5 +710,7 @@ |
InitializeLoadingAnimationData(&rb, &loading_animation_data); |
+ crashed_fav_icon = rb.GetBitmapNamed(IDR_SAD_FAVICON); |
+ |
initialized_ = true; |
} |