Home | History | Annotate | Download | only in infobars
      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/infobars/infobar.h"
      6 
      7 #include <cmath>
      8 
      9 #include "base/logging.h"
     10 #include "build/build_config.h"
     11 #include "chrome/browser/infobars/infobar_container.h"
     12 #include "chrome/browser/infobars/infobar_service.h"
     13 #include "ui/base/animation/slide_animation.h"
     14 
     15 SkColor GetInfoBarTopColor(InfoBarDelegate::Type infobar_type) {
     16   static const SkColor kWarningBackgroundColorTop =
     17       SkColorSetRGB(255, 242, 183);  // Yellow
     18   static const SkColor kPageActionBackgroundColorTop =
     19       SkColorSetRGB(237, 237, 237);  // Gray
     20   return (infobar_type == InfoBarDelegate::WARNING_TYPE) ?
     21       kWarningBackgroundColorTop : kPageActionBackgroundColorTop;
     22 }
     23 
     24 SkColor GetInfoBarBottomColor(InfoBarDelegate::Type infobar_type) {
     25   static const SkColor kWarningBackgroundColorBottom =
     26       SkColorSetRGB(250, 230, 145);  // Yellow
     27   static const SkColor kPageActionBackgroundColorBottom =
     28       SkColorSetRGB(217, 217, 217);  // Gray
     29   return (infobar_type == InfoBarDelegate::WARNING_TYPE) ?
     30       kWarningBackgroundColorBottom : kPageActionBackgroundColorBottom;
     31 }
     32 
     33 // TODO(pkasting): Port Mac to use this.
     34 #if defined(TOOLKIT_VIEWS) || defined(TOOLKIT_GTK) || defined(OS_ANDROID)
     35 
     36 InfoBar::InfoBar(InfoBarService* owner, InfoBarDelegate* delegate)
     37     : owner_(owner),
     38       delegate_(delegate),
     39       container_(NULL),
     40       animation_(this),
     41       arrow_height_(0),
     42       arrow_target_height_(kDefaultArrowTargetHeight),
     43       arrow_half_width_(0),
     44       bar_height_(0),
     45       bar_target_height_(kDefaultBarTargetHeight) {
     46   DCHECK(owner_ != NULL);
     47   DCHECK(delegate_ != NULL);
     48   animation_.SetTweenType(ui::Tween::LINEAR);
     49 }
     50 
     51 InfoBar::~InfoBar() {
     52 }
     53 
     54 void InfoBar::Show(bool animate) {
     55   PlatformSpecificShow(animate);
     56   if (animate) {
     57     animation_.Show();
     58   } else {
     59     animation_.Reset(1.0);
     60     RecalculateHeights(true);
     61   }
     62 }
     63 
     64 void InfoBar::Hide(bool animate) {
     65   PlatformSpecificHide(animate);
     66   if (animate) {
     67     animation_.Hide();
     68   } else {
     69     animation_.Reset(0.0);
     70     // We want to remove ourselves from the container immediately even if we
     71     // still have an owner, which MaybeDelete() won't do.
     72     DCHECK(container_);
     73     container_->RemoveInfoBar(this);
     74     MaybeDelete();  // Necessary if the infobar was already closing.
     75   }
     76 }
     77 
     78 void InfoBar::SetArrowTargetHeight(int height) {
     79   DCHECK_LE(height, kMaximumArrowTargetHeight);
     80   // Once the closing animation starts, we ignore further requests to change the
     81   // target height.
     82   if ((arrow_target_height_ != height) && !animation_.IsClosing()) {
     83     arrow_target_height_ = height;
     84     RecalculateHeights(false);
     85   }
     86 }
     87 
     88 void InfoBar::CloseSoon() {
     89   owner_ = NULL;
     90   PlatformSpecificOnCloseSoon();
     91   MaybeDelete();
     92 }
     93 
     94 void InfoBar::AnimationProgressed(const ui::Animation* animation) {
     95   RecalculateHeights(false);
     96 }
     97 
     98 void InfoBar::RemoveSelf() {
     99   // |owner_| should never be NULL here.  If it is, then someone violated what
    100   // they were supposed to do -- e.g. a ConfirmInfoBarDelegate subclass returned
    101   // true from Accept() or Cancel() even though the infobar was already closing.
    102   // In the worst case, if we also switched tabs during that process, then
    103   // |this| has already been destroyed.  But if that's the case, then we're
    104   // going to deref a garbage |this| pointer here whether we check |owner_| or
    105   // not, and in other cases (where we're still closing and |this| is valid),
    106   // checking |owner_| here will avoid a NULL deref.
    107   if (owner_)
    108     owner_->RemoveInfoBar(delegate_);
    109 }
    110 
    111 void InfoBar::SetBarTargetHeight(int height) {
    112   if (bar_target_height_ != height) {
    113     bar_target_height_ = height;
    114     RecalculateHeights(false);
    115   }
    116 }
    117 
    118 int InfoBar::OffsetY(const gfx::Size& prefsize) const {
    119   return arrow_height_ +
    120       std::max((bar_target_height_ - prefsize.height()) / 2, 0) -
    121       (bar_target_height_ - bar_height_);
    122 }
    123 
    124 void InfoBar::AnimationEnded(const ui::Animation* animation) {
    125   // When the animation ends, we must ensure the container is notified even if
    126   // the heights haven't changed, lest it never get an "animation finished"
    127   // notification.  (If the browser doesn't get this notification, it will not
    128   // bother to re-layout the content area for the new infobar size.)
    129   RecalculateHeights(true);
    130   MaybeDelete();
    131 }
    132 
    133 void InfoBar::RecalculateHeights(bool force_notify) {
    134   int old_arrow_height = arrow_height_;
    135   int old_bar_height = bar_height_;
    136 
    137   // Find the desired arrow height/half-width.  The arrow area is
    138   // |arrow_height_| * |arrow_half_width_|.  When the bar is opening or closing,
    139   // scaling each of these with the square root of the animation value causes a
    140   // linear animation of the area, which matches the perception of the animation
    141   // of the bar portion.
    142   double scale_factor = sqrt(animation_.GetCurrentValue());
    143   arrow_height_ = static_cast<int>(arrow_target_height_ * scale_factor);
    144   if (animation_.is_animating()) {
    145     arrow_half_width_ = static_cast<int>(std::min(arrow_target_height_,
    146         kMaximumArrowTargetHalfWidth) * scale_factor);
    147   } else {
    148     // When the infobar is not animating (i.e. fully open), we set the
    149     // half-width to be proportionally the same distance between its default and
    150     // maximum values as the height is between its.
    151     arrow_half_width_ = kDefaultArrowTargetHalfWidth +
    152         ((kMaximumArrowTargetHalfWidth - kDefaultArrowTargetHalfWidth) *
    153          ((arrow_height_ - kDefaultArrowTargetHeight) /
    154           (kMaximumArrowTargetHeight - kDefaultArrowTargetHeight)));
    155   }
    156   // Add pixels for the stroke, if the arrow is to be visible at all.  Without
    157   // this, changing the arrow height from 0 to kSeparatorLineHeight would
    158   // produce no visible effect, because the stroke would paint atop the divider
    159   // line above the infobar.
    160   if (arrow_height_)
    161     arrow_height_ += kSeparatorLineHeight;
    162 
    163   bar_height_ = animation_.CurrentValueBetween(0, bar_target_height_);
    164 
    165   // Don't re-layout if nothing has changed, e.g. because the animation step was
    166   // not large enough to actually change the heights by at least a pixel.
    167   bool heights_differ =
    168       (old_arrow_height != arrow_height_) || (old_bar_height != bar_height_);
    169   if (heights_differ)
    170     PlatformSpecificOnHeightsRecalculated();
    171 
    172   if (container_ && (heights_differ || force_notify))
    173     container_->OnInfoBarStateChanged(animation_.is_animating());
    174 }
    175 
    176 void InfoBar::MaybeDelete() {
    177   if (!owner_ && delegate_ && (animation_.GetCurrentValue() == 0.0)) {
    178     if (container_)
    179       container_->RemoveInfoBar(this);
    180     delete delegate_;
    181     delegate_ = NULL;
    182   }
    183 }
    184 
    185 #endif  // TOOLKIT_VIEWS || TOOLKIT_GTK || OS_ANDROID
    186