Index: ash/wm/frame_painter.cc |
diff --git a/ash/wm/frame_painter.cc b/ash/wm/frame_painter.cc |
index 6a14bbcb0930d5a174d6e62958ce866e7fd0a275..94b9504a78cae8a54f87e28abcba2e7e471625fc 100644 |
--- a/ash/wm/frame_painter.cc |
+++ b/ash/wm/frame_painter.cc |
@@ -16,6 +16,7 @@ |
#include "third_party/skia/include/core/SkShader.h" |
#include "ui/aura/client/aura_constants.h" |
#include "ui/aura/window.h" |
+#include "ui/base/animation/slide_animation.h" |
#include "ui/base/hit_test.h" |
#include "ui/base/resource/resource_bundle.h" |
#include "ui/base/theme_provider.h" |
@@ -70,6 +71,8 @@ const int kCloseButtonOffsetY = 0; |
// inset to preserve alignment with the NTP image, or else we'll break a bunch |
// of existing themes. We do something similar on OS X for the same reason. |
const int kThemeFrameBitmapOffsetX = 5; |
+// Duration of crossfade animation for activating and deactivating frame. |
+const int kActivationCrossfadeDurationMs = 200; |
// Tiles an image into an area, rounding the top corners. Samples the |bitmap| |
// starting |bitmap_offset_x| pixels from the left of the image. |
@@ -138,7 +141,12 @@ FramePainter::FramePainter() |
top_edge_(NULL), |
top_right_corner_(NULL), |
header_left_edge_(NULL), |
- header_right_edge_(NULL) { |
+ header_right_edge_(NULL), |
+ previous_theme_frame_(NULL), |
+ previous_opacity_(0), |
+ crossfade_theme_frame_(NULL), |
+ crossfade_opacity_(0), |
+ crossfade_animation_(NULL) { |
if (!instances_) |
instances_ = new std::set<FramePainter*>(); |
instances_->insert(this); |
@@ -283,10 +291,40 @@ void FramePainter::PaintHeader(views::NonClientFrameView* view, |
kSoloWindowOpacity : |
(header_mode == ACTIVE ? kActiveWindowOpacity : kInactiveWindowOpacity); |
+ if (previous_theme_frame_ && previous_theme_frame_ != theme_frame) { |
+ crossfade_animation_.reset(new ui::SlideAnimation(this)); |
+ crossfade_theme_frame_ = previous_theme_frame_; |
+ crossfade_opacity_ = previous_opacity_; |
+ crossfade_animation_->SetSlideDuration(kActivationCrossfadeDurationMs); |
+ crossfade_animation_->Show(); |
+ } |
+ |
+ header_frame_bounds_ = gfx::Rect(0, 0, view->width(), theme_frame->height()); |
+ |
+ const int kCornerRadius = 2; |
SkPaint paint; |
- paint.setAlpha(opacity); |
+ |
+ if (crossfade_animation_.get() && crossfade_animation_->is_animating()) { |
+ double current_value = crossfade_animation_->GetCurrentValue(); |
+ int old_alpha = (1 - current_value) * crossfade_opacity_; |
+ int new_alpha = current_value * opacity; |
+ |
+ // Draw the old header background, clipping the corners to be rounded. |
+ paint.setAlpha(old_alpha); |
+ paint.setXfermodeMode(SkXfermode::kPlus_Mode); |
+ TileRoundRect(canvas, |
+ 0, 0, view->width(), theme_frame->height(), |
+ &paint, |
+ *crossfade_theme_frame_, |
+ kCornerRadius, |
+ kThemeFrameBitmapOffsetX); |
+ |
+ paint.setAlpha(new_alpha); |
+ } else { |
+ paint.setAlpha(opacity); |
+ } |
+ |
// Draw the header background, clipping the corners to be rounded. |
- const int kCornerRadius = 2; |
TileRoundRect(canvas, |
0, 0, view->width(), theme_frame->height(), |
&paint, |
@@ -294,6 +332,9 @@ void FramePainter::PaintHeader(views::NonClientFrameView* view, |
kCornerRadius, |
kThemeFrameBitmapOffsetX); |
+ previous_theme_frame_ = theme_frame; |
+ previous_opacity_ = opacity; |
+ |
// Draw the theme frame overlay, if available. |
if (theme_frame_overlay) |
canvas->DrawBitmapInt(*theme_frame_overlay, 0, 0); |
@@ -471,6 +512,13 @@ void FramePainter::OnWindowDestroying(aura::Window* destroying) { |
} |
/////////////////////////////////////////////////////////////////////////////// |
+// ui::AnimationDelegate overrides: |
+ |
+void FramePainter::AnimationProgressed(const ui::Animation* animation) { |
+ frame_->SchedulePaintInRect(gfx::Rect(header_frame_bounds_)); |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
// FramePainter, private: |
void FramePainter::SetButtonImages(views::ImageButton* button, |