Home | History | Annotate | Download | only in 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 
     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 
    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 
    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 
    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 
    168 void DownloadStartedAnimationWin::Observe(NotificationType type,
    169                                           const NotificationSource& source,
    170                                           const NotificationDetails& details) {
    171   Close();
    172 }
    173 
    174 }  // namespace
    175 
    176 // static
    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