Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / views / location_bar / add_to_app_launcher_view.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 "chrome/browser/ui/views/location_bar/add_to_app_launcher_view.h"
6
7 #include "base/command_line.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
10 #include "chrome/common/chrome_switches.h"
11 #include "content/public/browser/web_contents.h"
12 #include "grit/generated_resources.h"
13 #include "grit/theme_resources.h"
14 #include "ui/base/l10n/l10n_util.h"
15 #include "ui/base/resource/resource_bundle.h"
16 #include "ui/gfx/color_utils.h"
17 #include "ui/views/controls/image_view.h"
18 #include "ui/views/controls/label.h"
19 #include "url/gurl.h"
20
21 namespace {
22
23 // TODO(benwells): Refactor common code between this and
24 // ContentSettingImageView.
25 const int kBackgroundImages[] = IMAGE_GRID(IDR_OMNIBOX_CONTENT_SETTING_BUBBLE);
26 const int kStayOpenTimeMS = 3200;  // Time spent with animation fully open.
27
28 const int kOpenTimeMS = 150;
29 const int kAnimationDurationMS = (kOpenTimeMS * 2) + kStayOpenTimeMS;
30
31 // Amount of padding at the edges of the bubble.  If |by_icon| is true, this
32 // is the padding next to the icon; otherwise it's the padding next to the
33 // label.  (We increase padding next to the label by the amount of padding
34 // "built in" to the icon in order to make the bubble appear to have
35 // symmetrical padding.)
36 int GetBubbleOuterPadding(bool by_icon) {
37   return LocationBarView::kItemPadding - LocationBarView::kBubblePadding +
38       (by_icon ? 0 : LocationBarView::kIconInternalPadding);
39 }
40
41 int GetTotalSpacingWhileAnimating() {
42   return GetBubbleOuterPadding(true) + LocationBarView::kItemPadding +
43       GetBubbleOuterPadding(false);
44 }
45
46 }  // namespace
47
48 AddToAppLauncherView::AddToAppLauncherView(LocationBarView* parent,
49                                            const gfx::FontList& font_list,
50                                            SkColor text_color,
51                                            SkColor parent_background_color)
52     : parent_(parent),
53       background_painter_(
54           views::Painter::CreateImageGridPainter(kBackgroundImages)),
55       icon_(new views::ImageView),
56       text_label_(new views::Label(base::string16(), font_list)),
57       slide_animator_(this) {
58   icon_->SetHorizontalAlignment(views::ImageView::LEADING);
59   icon_->SetImage(ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
60       IDR_BOOKMARK_BAR_APPS_SHORTCUT));
61   icon_->SetTooltipText(
62       base::UTF8ToUTF16(l10n_util::GetStringUTF8(IDS_ADD_TO_APP_LIST_HINT)));
63   AddChildView(icon_);
64
65   text_label_->SetVisible(false);
66   text_label_->SetEnabledColor(text_color);
67   // Calculate the actual background color for the label.  The background images
68   // are painted atop |parent_background_color|.  We grab the color of the
69   // middle pixel of the middle image of the background, which we treat as the
70   // representative color of the entire background (reasonable, given the
71   // current appearance of these images).  Then we alpha-blend it over the
72   // parent background color to determine the actual color the label text will
73   // sit atop.
74   const SkBitmap& bitmap(
75       ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
76           kBackgroundImages[4])->GetRepresentation(1.0f).sk_bitmap());
77   SkAutoLockPixels pixel_lock(bitmap);
78   SkColor background_image_color =
79       bitmap.getColor(bitmap.width() / 2, bitmap.height() / 2);
80   // Tricky bit: We alpha blend an opaque version of |background_image_color|
81   // against |parent_background_color| using the original image grid color's
82   // alpha. This is because AlphaBlend(a, b, 255) always returns |a| unchanged
83   // even if |a| is a color with non-255 alpha.
84   text_label_->SetBackgroundColor(
85       color_utils::AlphaBlend(SkColorSetA(background_image_color, 255),
86                               parent_background_color,
87                               SkColorGetA(background_image_color)));
88   text_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
89   text_label_->SetElideBehavior(gfx::NO_ELIDE);
90   text_label_->SetText(base::UTF8ToUTF16(
91       l10n_util::GetStringUTF8(IDS_ADD_TO_APP_LIST_NOTIFICATION_TEXT)));
92   AddChildView(text_label_);
93
94   slide_animator_.SetSlideDuration(kAnimationDurationMS);
95   slide_animator_.SetTweenType(gfx::Tween::LINEAR);
96 }
97
98 AddToAppLauncherView::~AddToAppLauncherView() {
99 }
100
101 void AddToAppLauncherView::Update(content::WebContents* web_contents) {
102   SetVisible(false);
103
104   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
105   if (!command_line->HasSwitch(switches::kEnableProminentURLAppFlow) ||
106       !command_line->HasSwitch(switches::kEnableStreamlinedHostedApps) ||
107       !web_contents || web_contents->IsLoading() ||
108       !web_contents->GetLastCommittedURL().SchemeIsHTTPOrHTTPS()) {
109     slide_animator_.Reset();
110     return;
111   }
112
113   SetVisible(true);
114
115   if (!slide_animator_.is_animating()) {
116     text_label_->SetVisible(true);
117     slide_animator_.Show();
118   }
119 }
120
121 void AddToAppLauncherView::AnimationEnded(const gfx::Animation* animation) {
122   slide_animator_.Reset();
123   text_label_->SetVisible(false);
124   AnimationProgressed(animation);
125 }
126
127 void AddToAppLauncherView::AnimationProgressed(
128     const gfx::Animation* animation) {
129   parent_->Layout();
130   parent_->SchedulePaint();
131 }
132
133 void AddToAppLauncherView::AnimationCanceled(const gfx::Animation* animation) {
134   AnimationEnded(animation);
135 }
136
137 gfx::Size AddToAppLauncherView::GetPreferredSize() const {
138   // Height will be ignored by the LocationBarView.
139   gfx::Size size(icon_->GetPreferredSize());
140   if (slide_animator_.is_animating()) {
141     double state = slide_animator_.GetCurrentValue();
142     // The fraction of the animation we'll spend animating the string into view,
143     // which is also the fraction we'll spend animating it closed; total
144     // animation (slide out, show, then slide in) is 1.0.
145     const double kOpenFraction =
146         static_cast<double>(kOpenTimeMS) / kAnimationDurationMS;
147     double size_fraction = 1.0;
148     if (state < kOpenFraction)
149       size_fraction = state / kOpenFraction;
150     if (state > (1.0 - kOpenFraction))
151       size_fraction = (1.0 - state) / kOpenFraction;
152     size.Enlarge(
153         size_fraction * (text_label_->GetPreferredSize().width() +
154             GetTotalSpacingWhileAnimating()), 0);
155     size.SetToMax(background_painter_->GetMinimumSize());
156   }
157   return size;
158 }
159
160 void AddToAppLauncherView::Layout() {
161   const int icon_width = icon_->GetPreferredSize().width();
162   icon_->SetBounds(
163       std::min((width() - icon_width) / 2, GetBubbleOuterPadding(true)),
164       0,
165       icon_width,
166       height());
167   text_label_->SetBounds(
168       icon_->bounds().right() + LocationBarView::kItemPadding,
169       0,
170       std::max(width() - GetTotalSpacingWhileAnimating() - icon_width, 0),
171       height());
172 }
173
174 void AddToAppLauncherView::OnPaintBackground(gfx::Canvas* canvas) {
175   if (slide_animator_.is_animating())
176     background_painter_->Paint(canvas, size());
177 }