Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / tabs / tab_utils.cc
1 // Copyright (c) 2012 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/tabs/tab_utils.h"
6
7 #include "base/strings/string16.h"
8 #include "chrome/browser/media/audio_stream_monitor.h"
9 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
10 #include "chrome/browser/media/media_stream_capture_indicator.h"
11 #include "grit/generated_resources.h"
12 #include "grit/theme_resources.h"
13 #include "ui/base/l10n/l10n_util.h"
14 #include "ui/base/resource/resource_bundle.h"
15 #include "ui/gfx/animation/multi_animation.h"
16
17 namespace chrome {
18
19 namespace {
20
21 // Interval between frame updates of the tab indicator animations.  This is not
22 // the usual 60 FPS because a trade-off must be made between tab UI animation
23 // smoothness and media recording/playback performance on low-end hardware.
24 const int kIndicatorFrameIntervalMs = 50;  // 20 FPS
25
26 // Fade-in/out duration for the tab indicator animations.  Fade-in is quick to
27 // immediately notify the user.  Fade-out is more gradual, so that the user has
28 // a chance of finding a tab that has quickly "blipped" on and off.
29 const int kIndicatorFadeInDurationMs = 200;
30 const int kIndicatorFadeOutDurationMs = 1000;
31
32 // Animation that throbs in (towards 1.0) and out (towards 0.0), and ends in the
33 // "in" state.
34 class TabRecordingIndicatorAnimation : public gfx::MultiAnimation {
35  public:
36   virtual ~TabRecordingIndicatorAnimation() {}
37
38   // Overridden to provide alternating "towards in" and "towards out" behavior.
39   virtual double GetCurrentValue() const OVERRIDE;
40
41   static scoped_ptr<TabRecordingIndicatorAnimation> Create();
42
43  private:
44   TabRecordingIndicatorAnimation(const gfx::MultiAnimation::Parts& parts,
45                                  const base::TimeDelta interval)
46       : MultiAnimation(parts, interval) {}
47
48   // Number of times to "toggle throb" the recording and tab capture indicators
49   // when they first appear.
50   static const int kCaptureIndicatorThrobCycles = 5;
51 };
52
53 double TabRecordingIndicatorAnimation::GetCurrentValue() const {
54   return current_part_index() % 2 ?
55       1.0 - MultiAnimation::GetCurrentValue() :
56       MultiAnimation::GetCurrentValue();
57 }
58
59 scoped_ptr<TabRecordingIndicatorAnimation>
60 TabRecordingIndicatorAnimation::Create() {
61   MultiAnimation::Parts parts;
62   COMPILE_ASSERT(kCaptureIndicatorThrobCycles % 2 != 0,
63                  must_be_odd_so_animation_finishes_in_showing_state);
64   for (int i = 0; i < kCaptureIndicatorThrobCycles; ++i) {
65     parts.push_back(MultiAnimation::Part(
66         i % 2 ? kIndicatorFadeOutDurationMs : kIndicatorFadeInDurationMs,
67         gfx::Tween::EASE_IN));
68   }
69   const base::TimeDelta interval =
70       base::TimeDelta::FromMilliseconds(kIndicatorFrameIntervalMs);
71   scoped_ptr<TabRecordingIndicatorAnimation> animation(
72       new TabRecordingIndicatorAnimation(parts, interval));
73   animation->set_continuous(false);
74   return animation.Pass();
75 }
76
77 }  // namespace
78
79 bool ShouldTabShowFavicon(int capacity,
80                           bool is_pinned_tab,
81                           bool is_active_tab,
82                           bool has_favicon,
83                           TabMediaState media_state) {
84   if (!has_favicon)
85     return false;
86   int required_capacity = 1;
87   if (ShouldTabShowCloseButton(capacity, is_pinned_tab, is_active_tab))
88     ++required_capacity;
89   if (ShouldTabShowMediaIndicator(
90           capacity, is_pinned_tab, is_active_tab, has_favicon, media_state)) {
91     ++required_capacity;
92   }
93   return capacity >= required_capacity;
94 }
95
96 bool ShouldTabShowMediaIndicator(int capacity,
97                                  bool is_pinned_tab,
98                                  bool is_active_tab,
99                                  bool has_favicon,
100                                  TabMediaState media_state) {
101   if (media_state == TAB_MEDIA_STATE_NONE)
102     return false;
103   if (ShouldTabShowCloseButton(capacity, is_pinned_tab, is_active_tab))
104     return capacity >= 2;
105   return capacity >= 1;
106 }
107
108 bool ShouldTabShowCloseButton(int capacity,
109                               bool is_pinned_tab,
110                               bool is_active_tab) {
111   if (is_pinned_tab)
112     return false;
113   else if (is_active_tab)
114     return true;
115   else
116     return capacity >= 3;
117 }
118
119 bool IsPlayingAudio(content::WebContents* contents) {
120   AudioStreamMonitor* const audio_stream_monitor =
121       AudioStreamMonitor::FromWebContents(contents);
122   return audio_stream_monitor && audio_stream_monitor->WasRecentlyAudible();
123 }
124
125 TabMediaState GetTabMediaStateForContents(content::WebContents* contents) {
126   if (!contents)
127     return TAB_MEDIA_STATE_NONE;
128
129   scoped_refptr<MediaStreamCaptureIndicator> indicator =
130       MediaCaptureDevicesDispatcher::GetInstance()->
131           GetMediaStreamCaptureIndicator();
132   if (indicator) {
133     if (indicator->IsBeingMirrored(contents))
134       return TAB_MEDIA_STATE_CAPTURING;
135     if (indicator->IsCapturingUserMedia(contents))
136       return TAB_MEDIA_STATE_RECORDING;
137   }
138
139   if (IsPlayingAudio(contents))
140     return TAB_MEDIA_STATE_AUDIO_PLAYING;
141
142   return TAB_MEDIA_STATE_NONE;
143 }
144
145 const gfx::Image& GetTabMediaIndicatorImage(TabMediaState media_state) {
146   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
147   switch (media_state) {
148     case TAB_MEDIA_STATE_AUDIO_PLAYING:
149       return rb.GetNativeImageNamed(IDR_TAB_AUDIO_INDICATOR);
150     case TAB_MEDIA_STATE_RECORDING:
151       return rb.GetNativeImageNamed(IDR_TAB_RECORDING_INDICATOR);
152     case TAB_MEDIA_STATE_CAPTURING:
153       return rb.GetNativeImageNamed(IDR_TAB_CAPTURE_INDICATOR);
154     case TAB_MEDIA_STATE_NONE:
155       break;
156   }
157   NOTREACHED();
158   return rb.GetNativeImageNamed(IDR_SAD_FAVICON);
159 }
160
161 scoped_ptr<gfx::Animation> CreateTabMediaIndicatorFadeAnimation(
162     TabMediaState media_state) {
163   if (media_state == TAB_MEDIA_STATE_RECORDING ||
164       media_state == TAB_MEDIA_STATE_CAPTURING) {
165     return TabRecordingIndicatorAnimation::Create().PassAs<gfx::Animation>();
166   }
167
168   // Note: While it seems silly to use a one-part MultiAnimation, it's the only
169   // gfx::Animation implementation that lets us control the frame interval.
170   gfx::MultiAnimation::Parts parts;
171   const bool is_for_fade_in = (media_state != TAB_MEDIA_STATE_NONE);
172   parts.push_back(gfx::MultiAnimation::Part(
173       is_for_fade_in ? kIndicatorFadeInDurationMs : kIndicatorFadeOutDurationMs,
174       gfx::Tween::EASE_IN));
175   const base::TimeDelta interval =
176       base::TimeDelta::FromMilliseconds(kIndicatorFrameIntervalMs);
177   scoped_ptr<gfx::MultiAnimation> animation(
178       new gfx::MultiAnimation(parts, interval));
179   animation->set_continuous(false);
180   return animation.PassAs<gfx::Animation>();
181 }
182
183 base::string16 AssembleTabTooltipText(const base::string16& title,
184                                       TabMediaState media_state) {
185   if (media_state == TAB_MEDIA_STATE_NONE)
186     return title;
187
188   base::string16 result = title;
189   if (!result.empty())
190     result.append(1, '\n');
191   switch (media_state) {
192     case TAB_MEDIA_STATE_AUDIO_PLAYING:
193       result.append(
194           l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_MEDIA_STATE_AUDIO_PLAYING));
195       break;
196     case TAB_MEDIA_STATE_RECORDING:
197       result.append(
198           l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_MEDIA_STATE_RECORDING));
199       break;
200     case TAB_MEDIA_STATE_CAPTURING:
201       result.append(
202           l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_MEDIA_STATE_CAPTURING));
203       break;
204     case TAB_MEDIA_STATE_NONE:
205       NOTREACHED();
206       break;
207   }
208   return result;
209 }
210
211 }  // namespace chrome