NaCl docs: add sanitizers to GSoC ideas
[chromium-blink-merge.git] / chrome / browser / ui / views / tabs / media_indicator_button.cc
blob8dec22aba0d950e348a45ca04cf10451ae7b9d93
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.
5 #include "chrome/browser/ui/views/tabs/media_indicator_button.h"
7 #include "chrome/browser/ui/views/tabs/tab.h"
8 #include "chrome/browser/ui/views/tabs/tab_controller.h"
9 #include "chrome/browser/ui/views/tabs/tab_renderer_data.h"
10 #include "content/public/browser/user_metrics.h"
11 #include "ui/gfx/animation/animation_delegate.h"
12 #include "ui/gfx/canvas.h"
13 #include "ui/gfx/image/image.h"
15 using base::UserMetricsAction;
17 const char MediaIndicatorButton::kViewClassName[] = "MediaIndicatorButton";
19 class MediaIndicatorButton::FadeAnimationDelegate
20 : public gfx::AnimationDelegate {
21 public:
22 explicit FadeAnimationDelegate(MediaIndicatorButton* button)
23 : button_(button) {}
24 ~FadeAnimationDelegate() override {}
26 private:
27 // gfx::AnimationDelegate
28 void AnimationProgressed(const gfx::Animation* animation) override {
29 button_->SchedulePaint();
32 void AnimationCanceled(const gfx::Animation* animation) override {
33 button_->showing_media_state_ = button_->media_state_;
34 button_->SchedulePaint();
37 void AnimationEnded(const gfx::Animation* animation) override {
38 button_->showing_media_state_ = button_->media_state_;
39 button_->SchedulePaint();
42 MediaIndicatorButton* const button_;
44 DISALLOW_COPY_AND_ASSIGN(FadeAnimationDelegate);
47 MediaIndicatorButton::MediaIndicatorButton()
48 : views::ImageButton(NULL),
49 media_state_(TAB_MEDIA_STATE_NONE),
50 showing_media_state_(TAB_MEDIA_STATE_NONE) {
51 SetEventTargeter(
52 scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this)));
55 MediaIndicatorButton::~MediaIndicatorButton() {}
57 void MediaIndicatorButton::TransitionToMediaState(TabMediaState next_state) {
58 if (next_state == media_state_)
59 return;
61 if (next_state != TAB_MEDIA_STATE_NONE) {
62 const gfx::ImageSkia* const indicator_image =
63 chrome::GetTabMediaIndicatorImage(next_state).ToImageSkia();
64 SetImage(views::CustomButton::STATE_NORMAL, indicator_image);
65 SetImage(views::CustomButton::STATE_DISABLED, indicator_image);
66 const gfx::ImageSkia* const affordance_image =
67 chrome::GetTabMediaIndicatorAffordanceImage(next_state).ToImageSkia();
68 SetImage(views::CustomButton::STATE_HOVERED, affordance_image);
69 SetImage(views::CustomButton::STATE_PRESSED, affordance_image);
72 if ((media_state_ == TAB_MEDIA_STATE_AUDIO_PLAYING &&
73 next_state == TAB_MEDIA_STATE_AUDIO_MUTING) ||
74 (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING &&
75 next_state == TAB_MEDIA_STATE_AUDIO_PLAYING) ||
76 (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING &&
77 next_state == TAB_MEDIA_STATE_NONE)) {
78 // Instant user feedback: No fade animation.
79 showing_media_state_ = next_state;
80 fade_animation_.reset();
81 } else {
82 if (next_state == TAB_MEDIA_STATE_NONE)
83 showing_media_state_ = media_state_; // Fading-out indicator.
84 else
85 showing_media_state_ = next_state; // Fading-in to next indicator.
86 fade_animation_ = chrome::CreateTabMediaIndicatorFadeAnimation(next_state);
87 if (!fade_animation_delegate_)
88 fade_animation_delegate_.reset(new FadeAnimationDelegate(this));
89 fade_animation_->set_delegate(fade_animation_delegate_.get());
90 fade_animation_->Start();
93 SetEnabled(chrome::IsTabAudioMutingFeatureEnabled() &&
94 (next_state == TAB_MEDIA_STATE_AUDIO_PLAYING ||
95 next_state == TAB_MEDIA_STATE_AUDIO_MUTING));
97 // An indicator state change should be made visible immediately, instead of
98 // the user being surprised when their mouse leaves the button.
99 if (state() == views::CustomButton::STATE_HOVERED) {
100 SetState(enabled() ? views::CustomButton::STATE_NORMAL :
101 views::CustomButton::STATE_DISABLED);
104 media_state_ = next_state;
106 // Note: The calls to SetImage(), SetEnabled(), and SetState() above will call
107 // SchedulePaint() if necessary.
110 const char* MediaIndicatorButton::GetClassName() const {
111 return kViewClassName;
114 views::View* MediaIndicatorButton::GetTooltipHandlerForPoint(
115 const gfx::Point& point) {
116 return NULL; // Tab (the parent View) provides the tooltip.
119 bool MediaIndicatorButton::OnMouseDragged(const ui::MouseEvent& event) {
120 const ButtonState previous_state = state();
121 const bool ret = ImageButton::OnMouseDragged(event);
122 if (previous_state != views::CustomButton::STATE_NORMAL &&
123 state() == views::CustomButton::STATE_NORMAL)
124 content::RecordAction(UserMetricsAction("MediaIndicatorButton_Dragged"));
125 return ret;
128 void MediaIndicatorButton::OnPaint(gfx::Canvas* canvas) {
129 double opaqueness =
130 fade_animation_ ? fade_animation_->GetCurrentValue() : 1.0;
131 if (media_state_ == TAB_MEDIA_STATE_NONE)
132 opaqueness = 1.0 - opaqueness; // Fading out, not in.
133 if (opaqueness < 1.0)
134 canvas->SaveLayerAlpha(opaqueness * SK_AlphaOPAQUE);
135 ImageButton::OnPaint(canvas);
136 if (opaqueness < 1.0)
137 canvas->Restore();
140 bool MediaIndicatorButton::DoesIntersectRect(const views::View* target,
141 const gfx::Rect& rect) const {
142 // If this button is not enabled, Tab (the parent View) handles all mouse
143 // events.
144 return enabled() &&
145 views::ViewTargeterDelegate::DoesIntersectRect(target, rect);
148 void MediaIndicatorButton::NotifyClick(const ui::Event& event) {
149 if (media_state_ == TAB_MEDIA_STATE_AUDIO_PLAYING)
150 content::RecordAction(UserMetricsAction("MediaIndicatorButton_Mute"));
151 else if (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING)
152 content::RecordAction(UserMetricsAction("MediaIndicatorButton_Unmute"));
153 else
154 NOTREACHED();
156 DCHECK(parent() && !strcmp(parent()->GetClassName(), Tab::kViewClassName));
157 Tab* const tab = static_cast<Tab*>(parent());
158 tab->controller()->ToggleTabAudioMute(tab);