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