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