• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/download/download_started_animation.h"
6 
7 #include "content/browser/tab_contents/tab_contents.h"
8 #include "content/common/notification_details.h"
9 #include "content/common/notification_registrar.h"
10 #include "content/common/notification_source.h"
11 #include "grit/theme_resources.h"
12 #include "ui/base/animation/linear_animation.h"
13 #include "ui/base/resource/resource_bundle.h"
14 #include "ui/gfx/rect.h"
15 #include "views/controls/image_view.h"
16 #include "views/widget/widget.h"
17 
18 // How long to spend moving downwards and fading out after waiting.
19 static const int kMoveTimeMs = 600;
20 
21 // The animation framerate.
22 static const int kFrameRateHz = 60;
23 
24 // What fraction of the frame height to move downward from the frame center.
25 // Note that setting this greater than 0.5 will mean moving past the bottom of
26 // the frame.
27 static const double kMoveFraction = 1.0 / 3.0;
28 
29 namespace {
30 
31 // DownloadStartAnimation creates an animation (which begins running
32 // immediately) that animates an image downward from the center of the frame
33 // provided on the constructor, while simultaneously fading it out.  To use,
34 // simply call "new DownloadStartAnimation"; the class cleans itself up when it
35 // finishes animating.
36 class DownloadStartedAnimationWin : public ui::LinearAnimation,
37                                     public NotificationObserver,
38                                     public views::ImageView {
39  public:
40   explicit DownloadStartedAnimationWin(TabContents* tab_contents);
41 
42  private:
43   // Move the animation to wherever it should currently be.
44   void Reposition();
45 
46   // Shut down the animation cleanly.
47   void Close();
48 
49   // Animation
50   virtual void AnimateToState(double state);
51 
52   // NotificationObserver
53   virtual void Observe(NotificationType type,
54                        const NotificationSource& source,
55                        const NotificationDetails& details);
56 
57   // We use a HWND for the popup so that it may float above any HWNDs in our UI.
58   views::Widget* popup_;
59 
60   // The content area holding us.
61   TabContents* tab_contents_;
62 
63   // The content area at the start of the animation. We store this so that the
64   // download shelf's resizing of the content area doesn't cause the animation
65   // to move around. This means that once started, the animation won't move
66   // with the parent window, but it's so fast that this shouldn't cause too
67   // much heartbreak.
68   gfx::Rect tab_contents_bounds_;
69 
70   // A scoped container for notification registries.
71   NotificationRegistrar registrar_;
72 
73   DISALLOW_COPY_AND_ASSIGN(DownloadStartedAnimationWin);
74 };
75 
DownloadStartedAnimationWin(TabContents * tab_contents)76 DownloadStartedAnimationWin::DownloadStartedAnimationWin(
77     TabContents* tab_contents)
78     : ui::LinearAnimation(kMoveTimeMs, kFrameRateHz, NULL),
79       popup_(NULL),
80       tab_contents_(tab_contents) {
81   static SkBitmap* kDownloadImage = NULL;
82   if (!kDownloadImage) {
83     kDownloadImage = ResourceBundle::GetSharedInstance().GetBitmapNamed(
84         IDR_DOWNLOAD_ANIMATION_BEGIN);
85   }
86 
87   // If we're too small to show the download image, then don't bother -
88   // the shelf will be enough.
89   tab_contents_->GetContainerBounds(&tab_contents_bounds_);
90   if (tab_contents_bounds_.height() < kDownloadImage->height())
91     return;
92 
93   registrar_.Add(
94       this,
95       NotificationType::TAB_CONTENTS_HIDDEN,
96       Source<TabContents>(tab_contents_));
97   registrar_.Add(
98       this,
99       NotificationType::TAB_CONTENTS_DESTROYED,
100       Source<TabContents>(tab_contents_));
101 
102   SetImage(kDownloadImage);
103 
104   gfx::Rect rc(0, 0, 0, 0);
105   views::Widget::CreateParams params(views::Widget::CreateParams::TYPE_POPUP);
106   params.transparent = true;
107   params.accept_events = false;
108   popup_ = views::Widget::CreateWidget(params);
109   popup_->SetOpacity(0x00);
110   popup_->Init(tab_contents_->GetNativeView(), rc);
111   popup_->SetContentsView(this);
112   Reposition();
113   popup_->Show();
114 
115   Start();
116 }
117 
Reposition()118 void DownloadStartedAnimationWin::Reposition() {
119   if (!tab_contents_)
120     return;
121 
122   // Align the image with the bottom left of the web contents (so that it
123   // points to the newly created download).
124   gfx::Size size = GetPreferredSize();
125   int x = base::i18n::IsRTL() ?
126       tab_contents_bounds_.right() - size.width() : tab_contents_bounds_.x();
127   popup_->SetBounds(gfx::Rect(
128       x,
129       static_cast<int>(tab_contents_bounds_.bottom() -
130           size.height() - size.height() * (1 - GetCurrentValue())),
131       size.width(),
132       size.height()));
133 }
134 
Close()135 void DownloadStartedAnimationWin::Close() {
136   if (!tab_contents_)
137     return;
138 
139   registrar_.Remove(
140       this,
141       NotificationType::TAB_CONTENTS_HIDDEN,
142       Source<TabContents>(tab_contents_));
143   registrar_.Remove(
144       this,
145       NotificationType::TAB_CONTENTS_DESTROYED,
146       Source<TabContents>(tab_contents_));
147   tab_contents_ = NULL;
148   popup_->Close();
149 }
150 
AnimateToState(double state)151 void DownloadStartedAnimationWin::AnimateToState(double state) {
152   if (state >= 1.0) {
153     Close();
154   } else {
155     Reposition();
156 
157     // Start at zero, peak halfway and end at zero.
158     double opacity = std::min(1.0 - pow(GetCurrentValue() - 0.5, 2) * 4.0,
159                               static_cast<double>(1.0));
160 
161     popup_->SetOpacity(
162         static_cast<SkColor>(opacity * 255.0));
163     SchedulePaint();  // Reposition() calls MoveWindow() which never picks up
164                       // alpha changes, so we need to force a paint.
165   }
166 }
167 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)168 void DownloadStartedAnimationWin::Observe(NotificationType type,
169                                           const NotificationSource& source,
170                                           const NotificationDetails& details) {
171   Close();
172 }
173 
174 }  // namespace
175 
176 // static
Show(TabContents * tab_contents)177 void DownloadStartedAnimation::Show(TabContents* tab_contents) {
178   // The animation will delete itself when it's finished or when the tab
179   // contents is hidden or destroyed.
180   new DownloadStartedAnimationWin(tab_contents);
181 }
182