Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / tabs / tab_utils.cc
blob9e2ba6896578db96b33c32fae54723a42ba36533
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.
5 #include "chrome/browser/ui/tabs/tab_utils.h"
7 #include "base/strings/string16.h"
8 #include "chrome/browser/media/audio_stream_indicator.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"
17 namespace chrome {
19 namespace {
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
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;
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() {}
38 // Overridden to provide alternating "towards in" and "towards out" behavior.
39 virtual double GetCurrentValue() const OVERRIDE;
41 static scoped_ptr<TabRecordingIndicatorAnimation> Create();
43 private:
44 TabRecordingIndicatorAnimation(const gfx::MultiAnimation::Parts& parts,
45 const base::TimeDelta interval)
46 : MultiAnimation(parts, interval) {}
48 // Number of times to "toggle throb" the recording and tab capture indicators
49 // when they first appear.
50 static const int kCaptureIndicatorThrobCycles = 5;
53 double TabRecordingIndicatorAnimation::GetCurrentValue() const {
54 return current_part_index() % 2 ?
55 1.0 - MultiAnimation::GetCurrentValue() :
56 MultiAnimation::GetCurrentValue();
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));
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();
77 } // namespace
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;
93 return capacity >= required_capacity;
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;
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;
119 bool IsPlayingAudio(content::WebContents* contents) {
120 AudioStreamIndicator* audio_indicator =
121 MediaCaptureDevicesDispatcher::GetInstance()->GetAudioStreamIndicator()
122 .get();
123 return audio_indicator && audio_indicator->IsPlayingAudio(contents);
126 TabMediaState GetTabMediaStateForContents(content::WebContents* contents) {
127 if (!contents)
128 return TAB_MEDIA_STATE_NONE;
130 scoped_refptr<MediaStreamCaptureIndicator> indicator =
131 MediaCaptureDevicesDispatcher::GetInstance()->
132 GetMediaStreamCaptureIndicator();
133 if (indicator) {
134 if (indicator->IsBeingMirrored(contents))
135 return TAB_MEDIA_STATE_CAPTURING;
136 if (indicator->IsCapturingUserMedia(contents))
137 return TAB_MEDIA_STATE_RECORDING;
140 if (IsPlayingAudio(contents))
141 return TAB_MEDIA_STATE_AUDIO_PLAYING;
143 return TAB_MEDIA_STATE_NONE;
146 const gfx::Image& GetTabMediaIndicatorImage(TabMediaState media_state) {
147 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
148 switch (media_state) {
149 case TAB_MEDIA_STATE_AUDIO_PLAYING:
150 return rb.GetNativeImageNamed(IDR_TAB_AUDIO_INDICATOR);
151 case TAB_MEDIA_STATE_RECORDING:
152 return rb.GetNativeImageNamed(IDR_TAB_RECORDING_INDICATOR);
153 case TAB_MEDIA_STATE_CAPTURING:
154 return rb.GetNativeImageNamed(IDR_TAB_CAPTURE_INDICATOR);
155 case TAB_MEDIA_STATE_NONE:
156 break;
158 NOTREACHED();
159 return rb.GetNativeImageNamed(IDR_SAD_FAVICON);
162 scoped_ptr<gfx::Animation> CreateTabMediaIndicatorFadeAnimation(
163 TabMediaState media_state) {
164 if (media_state == TAB_MEDIA_STATE_RECORDING ||
165 media_state == TAB_MEDIA_STATE_CAPTURING) {
166 return TabRecordingIndicatorAnimation::Create().PassAs<gfx::Animation>();
169 // Note: While it seems silly to use a one-part MultiAnimation, it's the only
170 // gfx::Animation implementation that lets us control the frame interval.
171 gfx::MultiAnimation::Parts parts;
172 const bool is_for_fade_in = (media_state != TAB_MEDIA_STATE_NONE);
173 parts.push_back(gfx::MultiAnimation::Part(
174 is_for_fade_in ? kIndicatorFadeInDurationMs : kIndicatorFadeOutDurationMs,
175 gfx::Tween::EASE_IN));
176 const base::TimeDelta interval =
177 base::TimeDelta::FromMilliseconds(kIndicatorFrameIntervalMs);
178 scoped_ptr<gfx::MultiAnimation> animation(
179 new gfx::MultiAnimation(parts, interval));
180 animation->set_continuous(false);
181 return animation.PassAs<gfx::Animation>();
184 base::string16 AssembleTabTooltipText(const base::string16& title,
185 TabMediaState media_state) {
186 if (media_state == TAB_MEDIA_STATE_NONE)
187 return title;
189 base::string16 result = title;
190 if (!result.empty())
191 result.append(1, '\n');
192 switch (media_state) {
193 case TAB_MEDIA_STATE_AUDIO_PLAYING:
194 result.append(
195 l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_MEDIA_STATE_AUDIO_PLAYING));
196 break;
197 case TAB_MEDIA_STATE_RECORDING:
198 result.append(
199 l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_MEDIA_STATE_RECORDING));
200 break;
201 case TAB_MEDIA_STATE_CAPTURING:
202 result.append(
203 l10n_util::GetStringUTF16(IDS_TOOLTIP_TAB_MEDIA_STATE_CAPTURING));
204 break;
205 case TAB_MEDIA_STATE_NONE:
206 NOTREACHED();
207 break;
209 return result;
212 } // namespace chrome