Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(197)

Side by Side Diff: chrome/browser/ui/views/tabs/tab.cc

Issue 591963002: Tab audio mute control (views UI), behind a switch (off by default). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed mpearson's comments; added a few CloseTab UMA's. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/views/tabs/tab.h" 5 #include "chrome/browser/ui/views/tabs/tab.h"
6 6
7 #include <limits> 7 #include <limits>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/debug/alias.h" 10 #include "base/debug/alias.h"
11 #include "base/strings/utf_string_conversions.h" 11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/defaults.h" 12 #include "chrome/browser/defaults.h"
13 #include "chrome/browser/themes/theme_properties.h" 13 #include "chrome/browser/themes/theme_properties.h"
14 #include "chrome/browser/ui/browser.h" 14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/tab_contents/core_tab_helper.h" 15 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
16 #include "chrome/browser/ui/tabs/tab_resources.h" 16 #include "chrome/browser/ui/tabs/tab_resources.h"
17 #include "chrome/browser/ui/tabs/tab_utils.h" 17 #include "chrome/browser/ui/tabs/tab_utils.h"
18 #include "chrome/browser/ui/view_ids.h" 18 #include "chrome/browser/ui/view_ids.h"
19 #include "chrome/browser/ui/views/tabs/tab_controller.h" 19 #include "chrome/browser/ui/views/tabs/tab_controller.h"
20 #include "chrome/browser/ui/views/theme_image_mapper.h" 20 #include "chrome/browser/ui/views/theme_image_mapper.h"
21 #include "chrome/browser/ui/views/touch_uma/touch_uma.h" 21 #include "chrome/browser/ui/views/touch_uma/touch_uma.h"
22 #include "chrome/common/chrome_switches.h" 22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/grit/generated_resources.h" 23 #include "chrome/grit/generated_resources.h"
24 #include "content/public/browser/user_metrics.h"
24 #include "grit/theme_resources.h" 25 #include "grit/theme_resources.h"
25 #include "third_party/skia/include/effects/SkGradientShader.h" 26 #include "third_party/skia/include/effects/SkGradientShader.h"
26 #include "ui/accessibility/ax_view_state.h" 27 #include "ui/accessibility/ax_view_state.h"
27 #include "ui/aura/env.h" 28 #include "ui/aura/env.h"
28 #include "ui/base/l10n/l10n_util.h" 29 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/base/models/list_selection_model.h" 30 #include "ui/base/models/list_selection_model.h"
30 #include "ui/base/resource/resource_bundle.h" 31 #include "ui/base/resource/resource_bundle.h"
31 #include "ui/base/theme_provider.h" 32 #include "ui/base/theme_provider.h"
32 #include "ui/gfx/animation/animation_container.h" 33 #include "ui/gfx/animation/animation_container.h"
33 #include "ui/gfx/animation/multi_animation.h" 34 #include "ui/gfx/animation/multi_animation.h"
34 #include "ui/gfx/animation/throb_animation.h" 35 #include "ui/gfx/animation/throb_animation.h"
35 #include "ui/gfx/canvas.h" 36 #include "ui/gfx/canvas.h"
36 #include "ui/gfx/color_analysis.h" 37 #include "ui/gfx/color_analysis.h"
37 #include "ui/gfx/favicon_size.h" 38 #include "ui/gfx/favicon_size.h"
38 #include "ui/gfx/image/image_skia_operations.h" 39 #include "ui/gfx/image/image_skia_operations.h"
39 #include "ui/gfx/path.h" 40 #include "ui/gfx/path.h"
40 #include "ui/gfx/rect_conversions.h" 41 #include "ui/gfx/rect_conversions.h"
41 #include "ui/gfx/skia_util.h" 42 #include "ui/gfx/skia_util.h"
42 #include "ui/resources/grit/ui_resources.h" 43 #include "ui/resources/grit/ui_resources.h"
43 #include "ui/views/border.h" 44 #include "ui/views/border.h"
44 #include "ui/views/controls/button/image_button.h" 45 #include "ui/views/controls/button/image_button.h"
45 #include "ui/views/controls/label.h" 46 #include "ui/views/controls/label.h"
46 #include "ui/views/rect_based_targeting_utils.h" 47 #include "ui/views/rect_based_targeting_utils.h"
47 #include "ui/views/view_targeter.h" 48 #include "ui/views/view_targeter.h"
48 #include "ui/views/widget/tooltip_manager.h" 49 #include "ui/views/widget/tooltip_manager.h"
49 #include "ui/views/widget/widget.h" 50 #include "ui/views/widget/widget.h"
50 #include "ui/views/window/non_client_view.h" 51 #include "ui/views/window/non_client_view.h"
51 52
53 using base::UserMetricsAction;
54
52 namespace { 55 namespace {
53 56
54 // Padding around the "content" of a tab, occupied by the tab border graphics. 57 // Padding around the "content" of a tab, occupied by the tab border graphics.
55 const int kLeftPadding = 22; 58 const int kLeftPadding = 22;
56 const int kTopPadding = 4; 59 const int kTopPadding = 4;
57 const int kRightPadding = 17; 60 const int kRightPadding = 17;
58 const int kBottomPadding = 2; 61 const int kBottomPadding = 2;
59 62
60 // Height of the shadow at the top of the tab image assets. 63 // Height of the shadow at the top of the tab image assets.
61 const int kDropShadowHeight = 4; 64 const int kDropShadowHeight = 4;
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 const SkColor kImmersiveInactiveTabColor = SkColorSetRGB(190, 190, 190); 128 const SkColor kImmersiveInactiveTabColor = SkColorSetRGB(190, 190, 190);
126 129
127 // The minimum opacity (out of 1) when a tab (either active or inactive) is 130 // The minimum opacity (out of 1) when a tab (either active or inactive) is
128 // throbbing in the immersive mode light strip. 131 // throbbing in the immersive mode light strip.
129 const double kImmersiveTabMinThrobOpacity = 0.66; 132 const double kImmersiveTabMinThrobOpacity = 0.66;
130 133
131 // Number of steps in the immersive mode loading animation. 134 // Number of steps in the immersive mode loading animation.
132 const int kImmersiveLoadingStepCount = 32; 135 const int kImmersiveLoadingStepCount = 32;
133 136
134 const char kTabCloseButtonName[] = "TabCloseButton"; 137 const char kTabCloseButtonName[] = "TabCloseButton";
138 const char kMediaIndicatorButtonName[] = "MediaIndicatorButton";
135 139
136 void DrawIconAtLocation(gfx::Canvas* canvas, 140 void DrawIconAtLocation(gfx::Canvas* canvas,
137 const gfx::ImageSkia& image, 141 const gfx::ImageSkia& image,
138 int image_offset, 142 int image_offset,
139 int dst_x, 143 int dst_x,
140 int dst_y, 144 int dst_y,
141 int icon_width, 145 int icon_width,
142 int icon_height, 146 int icon_height,
143 bool filter, 147 bool filter,
144 const SkPaint& paint) { 148 const SkPaint& paint) {
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 375
372 return MaskedTargeterDelegate::DoesIntersectRect(target, rect); 376 return MaskedTargeterDelegate::DoesIntersectRect(target, rect);
373 } 377 }
374 378
375 Tab* tab_; 379 Tab* tab_;
376 380
377 DISALLOW_COPY_AND_ASSIGN(TabCloseButton); 381 DISALLOW_COPY_AND_ASSIGN(TabCloseButton);
378 }; 382 };
379 383
380 //////////////////////////////////////////////////////////////////////////////// 384 ////////////////////////////////////////////////////////////////////////////////
385 // MediaIndicatorButton
386 //
387 // This is a Button subclass that serves as both the media indicator icon
388 // (audio, tab capture, etc.), and as a mute button. When the indicator is
389 // transitioned to the audio playing or muting state, the button functionality
390 // is enabled and begins handling mouse events. Otherwise, this view behaves
391 // like an image and all mouse events will be handled by the Tab (its parent
392 // View).
393 class Tab::MediaIndicatorButton : public views::ImageButton,
sky 2014/09/23 22:58:18 Move this into its own .h/.cc.
miu 2014/09/24 22:34:16 Done.
394 public views::ViewTargeterDelegate {
395 public:
396 explicit MediaIndicatorButton(Tab* tab)
sky 2014/09/23 22:58:18 You don't seem to use tab at all here.
miu 2014/09/24 22:34:16 Done. Yep, I can downcast from View::parent() whe
397 : views::ImageButton(NULL),
398 media_state_(TAB_MEDIA_STATE_NONE),
399 showing_media_state_(TAB_MEDIA_STATE_NONE) {
400 SetEventTargeter(
401 scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this)));
402 }
403
404 virtual ~MediaIndicatorButton() {}
405
406 // Returns the current TabMediaState except, while the indicator image is
407 // fading out, returns the prior TabMediaState.
408 TabMediaState showing_media_state() const {
409 return showing_media_state_;
410 }
411
412 // Updates ImageButton images, starts fade animations, and
413 // activates/deactivates button functionality as appropriate.
414 void TransitionToMediaState(TabMediaState next_state) {
415 if (next_state == media_state_)
416 return;
417
418 if (next_state != TAB_MEDIA_STATE_NONE) {
419 const gfx::ImageSkia* const indicator_image =
420 chrome::GetTabMediaIndicatorImage(next_state).ToImageSkia();
421 SetImage(views::CustomButton::STATE_NORMAL, indicator_image);
422 SetImage(views::CustomButton::STATE_DISABLED, indicator_image);
423 const gfx::ImageSkia* const affordance_image =
424 chrome::GetTabMediaIndicatorAffordanceImage(next_state).ToImageSkia();
425 SetImage(views::CustomButton::STATE_HOVERED, affordance_image);
426 SetImage(views::CustomButton::STATE_PRESSED, affordance_image);
427 }
428
429 if ((media_state_ == TAB_MEDIA_STATE_AUDIO_PLAYING &&
430 next_state == TAB_MEDIA_STATE_AUDIO_MUTING) ||
431 (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING &&
432 next_state == TAB_MEDIA_STATE_AUDIO_PLAYING) ||
433 (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING &&
434 next_state == TAB_MEDIA_STATE_NONE)) {
435 // Instant user feedback: No fade animation.
436 showing_media_state_ = next_state;
437 media_indicator_animation_.reset();
438 } else {
439 if (next_state == TAB_MEDIA_STATE_NONE)
440 showing_media_state_ = media_state_; // Fading-out indicator.
441 else
442 showing_media_state_ = next_state; // Fading-in to next indicator.
443 media_indicator_animation_ =
444 chrome::CreateTabMediaIndicatorFadeAnimation(next_state);
445 media_indicator_animation_->set_delegate(this);
446 media_indicator_animation_->Start();
447 }
448
449 SetEnabled(chrome::IsTabAudioMutingFeatureEnabled() &&
450 (next_state == TAB_MEDIA_STATE_AUDIO_PLAYING ||
451 next_state == TAB_MEDIA_STATE_AUDIO_MUTING));
452
453 // An indicator state change should be made visible immediately, instead of
454 // the user being surprised when their mouse leaves the button.
455 if (state() == views::CustomButton::STATE_HOVERED) {
456 SetState(enabled() ? views::CustomButton::STATE_NORMAL :
457 views::CustomButton::STATE_DISABLED);
458 }
459
460 media_state_ = next_state;
461 }
462
463 protected:
464 // views::View:
465 virtual const char* GetClassName() const OVERRIDE {
466 return kMediaIndicatorButtonName;
467 }
468
469 virtual View* GetTooltipHandlerForPoint(const gfx::Point& point) OVERRIDE {
470 return NULL; // Tab (the parent View) provides the tooltip.
471 }
472
473 virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE {
474 const ButtonState previous_state = state();
475 const bool ret = ImageButton::OnMouseDragged(event);
476 if (previous_state != views::CustomButton::STATE_NORMAL &&
477 state() == views::CustomButton::STATE_NORMAL)
478 content::RecordAction(UserMetricsAction("MediaIndicatorButton_Dragged"));
479 return ret;
480 }
481
482 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
483 double opaqueness = media_indicator_animation_ ?
484 media_indicator_animation_->GetCurrentValue() : 1.0;
485 if (media_state_ == TAB_MEDIA_STATE_NONE)
486 opaqueness = 1.0 - opaqueness; // Fading out, not in.
sky 2014/09/23 22:58:18 Can't you make the animation return the right valu
miu 2014/09/24 22:34:16 I think it goes against the intentions of gfx::Ani
sky 2014/09/25 19:25:04 Well, it depends upon the animation. In theory you
487 if (opaqueness < 1.0)
488 canvas->SaveLayerAlpha(opaqueness * SK_AlphaOPAQUE);
489 ImageButton::OnPaint(canvas);
490 if (opaqueness < 1.0)
491 canvas->Restore();
492 }
493
494 // views::ViewTargeterDelegate
495 virtual bool DoesIntersectRect(const View* target,
496 const gfx::Rect& rect) const OVERRIDE {
497 // If this button is not enabled, Tab (the parent View) handles all mouse
498 // events.
499 return enabled() &&
500 views::ViewTargeterDelegate::DoesIntersectRect(target, rect);
501 }
502
503 // views::Button:
504 virtual void NotifyClick(const ui::Event& event) OVERRIDE {
sky 2014/09/23 22:58:17 Is it going to be annoying that the behavior of th
miu 2014/09/24 22:34:16 (I assume you're referring to the code/comment at
sky 2014/09/25 19:25:04 Just in general because the state may change at an
505 if (media_state_ == TAB_MEDIA_STATE_AUDIO_PLAYING)
506 content::RecordAction(UserMetricsAction("MuteTab"));
507 else if (media_state_ == TAB_MEDIA_STATE_AUDIO_MUTING)
508 content::RecordAction(UserMetricsAction("UnmuteTab"));
509 else
510 NOTREACHED();
511
512 if (Tab* const tab = static_cast<Tab*>(parent()))
sky 2014/09/23 22:58:18 Can the parent really be NULL? I would expect this
miu 2014/09/24 22:34:16 Done.
513 tab->controller_->ToggleTabAudioMute(tab);
514 }
515
516 // gfx::AnimationDelegate
517 virtual void AnimationCanceled(const gfx::Animation* animation) OVERRIDE {
sky 2014/09/23 22:58:18 Having ImageButton be the delegate for two animati
miu 2014/09/24 22:34:16 Done.
518 showing_media_state_ = media_state_;
519 ImageButton::AnimationCanceled(animation);
520 SchedulePaint();
521 }
522
523 virtual void AnimationEnded(const gfx::Animation* animation) OVERRIDE {
524 showing_media_state_ = media_state_;
525 ImageButton::AnimationEnded(animation);
526 SchedulePaint();
527 }
528
529 private:
530 TabMediaState media_state_;
531
532 // Media indicator fade-in/out animation (i.e., only on show/hide, not a
533 // continuous animation).
534 scoped_ptr<gfx::Animation> media_indicator_animation_;
535 TabMediaState showing_media_state_;
536
537 DISALLOW_COPY_AND_ASSIGN(MediaIndicatorButton);
538 };
539
540 ////////////////////////////////////////////////////////////////////////////////
381 // ImageCacheEntry 541 // ImageCacheEntry
382 542
383 Tab::ImageCacheEntry::ImageCacheEntry() 543 Tab::ImageCacheEntry::ImageCacheEntry()
384 : resource_id(-1), 544 : resource_id(-1),
385 scale_factor(ui::SCALE_FACTOR_NONE) { 545 scale_factor(ui::SCALE_FACTOR_NONE) {
386 } 546 }
387 547
388 Tab::ImageCacheEntry::~ImageCacheEntry() {} 548 Tab::ImageCacheEntry::~ImageCacheEntry() {}
389 549
390 //////////////////////////////////////////////////////////////////////////////// 550 ////////////////////////////////////////////////////////////////////////////////
(...skipping 11 matching lines...) Expand all
402 562
403 Tab::Tab(TabController* controller) 563 Tab::Tab(TabController* controller)
404 : controller_(controller), 564 : controller_(controller),
405 closing_(false), 565 closing_(false),
406 dragging_(false), 566 dragging_(false),
407 detached_(false), 567 detached_(false),
408 favicon_hiding_offset_(0), 568 favicon_hiding_offset_(0),
409 loading_animation_frame_(0), 569 loading_animation_frame_(0),
410 immersive_loading_step_(0), 570 immersive_loading_step_(0),
411 should_display_crashed_favicon_(false), 571 should_display_crashed_favicon_(false),
412 animating_media_state_(TAB_MEDIA_STATE_NONE),
413 close_button_(NULL), 572 close_button_(NULL),
573 media_indicator_button_(NULL),
414 title_(new views::Label()), 574 title_(new views::Label()),
415 tab_activated_with_last_tap_down_(false), 575 tab_activated_with_last_tap_down_(false),
416 hover_controller_(this), 576 hover_controller_(this),
417 showing_icon_(false), 577 showing_icon_(false),
418 showing_media_indicator_(false), 578 showing_media_indicator_(false),
419 showing_close_button_(false), 579 showing_close_button_(false),
420 close_button_color_(0) { 580 close_button_color_(0) {
421 DCHECK(controller); 581 DCHECK(controller);
422 InitTabResources(); 582 InitTabResources();
423 583
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
502 #else 662 #else
503 StartCrashAnimation(); 663 StartCrashAnimation();
504 #endif 664 #endif
505 } 665 }
506 } else { 666 } else {
507 if (IsPerformingCrashAnimation()) 667 if (IsPerformingCrashAnimation())
508 StopCrashAnimation(); 668 StopCrashAnimation();
509 ResetCrashedFavicon(); 669 ResetCrashedFavicon();
510 } 670 }
511 671
512 if (data_.media_state != old.media_state) { 672 if (data_.media_state != old.media_state)
513 if (data_.media_state != TAB_MEDIA_STATE_NONE) 673 LazyGetMediaIndicatorButton()->TransitionToMediaState(data_.media_state);
514 animating_media_state_ = data_.media_state;
515 StartMediaIndicatorAnimation();
516 }
517 674
518 if (old.mini != data_.mini) { 675 if (old.mini != data_.mini) {
519 StopAndDeleteAnimation( 676 StopAndDeleteAnimation(
520 mini_title_change_animation_.PassAs<gfx::Animation>()); 677 mini_title_change_animation_.PassAs<gfx::Animation>());
521 } 678 }
522 679
523 DataChanged(old); 680 DataChanged(old);
524 681
525 Layout(); 682 Layout();
526 SchedulePaint(); 683 SchedulePaint();
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
635 792
636 void Tab::AnimationProgressed(const gfx::Animation* animation) { 793 void Tab::AnimationProgressed(const gfx::Animation* animation) {
637 // Ignore if the pulse animation is being performed on active tab because 794 // Ignore if the pulse animation is being performed on active tab because
638 // it repaints the same image. See |Tab::PaintTabBackground()|. 795 // it repaints the same image. See |Tab::PaintTabBackground()|.
639 if (animation == pulse_animation_.get() && IsActive()) 796 if (animation == pulse_animation_.get() && IsActive())
640 return; 797 return;
641 SchedulePaint(); 798 SchedulePaint();
642 } 799 }
643 800
644 void Tab::AnimationCanceled(const gfx::Animation* animation) { 801 void Tab::AnimationCanceled(const gfx::Animation* animation) {
645 if (media_indicator_animation_ == animation)
646 animating_media_state_ = data_.media_state;
647 SchedulePaint(); 802 SchedulePaint();
648 } 803 }
649 804
650 void Tab::AnimationEnded(const gfx::Animation* animation) { 805 void Tab::AnimationEnded(const gfx::Animation* animation) {
651 if (media_indicator_animation_ == animation)
652 animating_media_state_ = data_.media_state;
653 SchedulePaint(); 806 SchedulePaint();
654 } 807 }
655 808
656 //////////////////////////////////////////////////////////////////////////////// 809 ////////////////////////////////////////////////////////////////////////////////
657 // Tab, views::ButtonListener overrides: 810 // Tab, views::ButtonListener overrides:
658 811
659 void Tab::ButtonPressed(views::Button* sender, const ui::Event& event) { 812 void Tab::ButtonPressed(views::Button* sender, const ui::Event& event) {
813 if (media_indicator_button_ && media_indicator_button_->visible()) {
814 if (media_indicator_button_->enabled())
Mark P 2014/09/23 18:56:15 Are you planning to do sequence analysis? If not,
815 content::RecordAction(UserMetricsAction("CloseTab_MuteToggleAvailable"));
816 else if (data_.media_state == TAB_MEDIA_STATE_AUDIO_PLAYING)
817 content::RecordAction(UserMetricsAction("CloseTab_AudioIndicator"));
818 else
819 content::RecordAction(UserMetricsAction("CloseTab_CaptureIndicator"));
Mark P 2014/09/23 19:49:56 Can you please give this a better name?
miu 2014/09/24 22:34:16 Done. Named it RecordingIndicator, per offline IM
820 } else {
821 content::RecordAction(UserMetricsAction("CloseTab_NoMediaIndicator"));
822 }
823
660 const CloseTabSource source = 824 const CloseTabSource source =
661 (event.type() == ui::ET_MOUSE_RELEASED && 825 (event.type() == ui::ET_MOUSE_RELEASED &&
662 (event.flags() & ui::EF_FROM_TOUCH) == 0) ? CLOSE_TAB_FROM_MOUSE : 826 (event.flags() & ui::EF_FROM_TOUCH) == 0) ? CLOSE_TAB_FROM_MOUSE :
663 CLOSE_TAB_FROM_TOUCH; 827 CLOSE_TAB_FROM_TOUCH;
664 DCHECK_EQ(close_button_, sender); 828 DCHECK_EQ(close_button_, sender);
665 controller_->CloseTab(this, source); 829 controller_->CloseTab(this, source);
666 if (event.type() == ui::ET_GESTURE_TAP) 830 if (event.type() == ui::ET_GESTURE_TAP)
667 TouchUMA::RecordGestureAction(TouchUMA::GESTURE_TABCLOSE_TAP); 831 TouchUMA::RecordGestureAction(TouchUMA::GESTURE_TABCLOSE_TAP);
668 } 832 }
669 833
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
763 const int left = kViewSpacing; 927 const int left = kViewSpacing;
764 const int right = width() - (lb.width() + close_button_size.width() + left); 928 const int right = width() - (lb.width() + close_button_size.width() + left);
765 close_button_->SetBorder( 929 close_button_->SetBorder(
766 views::Border::CreateEmptyBorder(top, left, bottom, right)); 930 views::Border::CreateEmptyBorder(top, left, bottom, right));
767 close_button_->SetPosition(gfx::Point(lb.width(), 0)); 931 close_button_->SetPosition(gfx::Point(lb.width(), 0));
768 close_button_->SizeToPreferredSize(); 932 close_button_->SizeToPreferredSize();
769 } 933 }
770 close_button_->SetVisible(showing_close_button_); 934 close_button_->SetVisible(showing_close_button_);
771 935
772 showing_media_indicator_ = ShouldShowMediaIndicator(); 936 showing_media_indicator_ = ShouldShowMediaIndicator();
773 media_indicator_bounds_.SetRect(lb.x(), lb.y(), 0, 0);
774 if (showing_media_indicator_) { 937 if (showing_media_indicator_) {
775 const gfx::Image& media_indicator_image = 938 views::ImageButton* const button = LazyGetMediaIndicatorButton();
776 chrome::GetTabMediaIndicatorImage(animating_media_state_); 939 const gfx::Size image_size(button->GetPreferredSize());
777 media_indicator_bounds_.set_width(media_indicator_image.Width());
778 media_indicator_bounds_.set_height(media_indicator_image.Height());
779 media_indicator_bounds_.set_y(
780 lb.y() + (lb.height() - media_indicator_bounds_.height() + 1) / 2);
781 const int right = showing_close_button_ ? 940 const int right = showing_close_button_ ?
782 close_button_->x() + close_button_->GetInsets().left() : lb.right(); 941 close_button_->x() + close_button_->GetInsets().left() : lb.right();
783 media_indicator_bounds_.set_x( 942 gfx::Rect bounds(
784 std::max(lb.x(), right - media_indicator_bounds_.width())); 943 std::max(lb.x(), right - image_size.width()),
785 MaybeAdjustLeftForMiniTab(&media_indicator_bounds_); 944 lb.y() + (lb.height() - image_size.height() + 1) / 2,
945 image_size.width(),
946 image_size.height());
947 MaybeAdjustLeftForMiniTab(&bounds);
948 button->SetBoundsRect(bounds);
sky 2014/09/23 22:58:18 Did you make sure this does the right thing when r
miu 2014/09/24 22:34:15 Good thing you had me check. When I first impleme
949 button->SetVisible(true);
950 } else if (media_indicator_button_) {
951 media_indicator_button_->SetVisible(false);
786 } 952 }
787 953
788 // Size the title to fill the remaining width and use all available height. 954 // Size the title to fill the remaining width and use all available height.
789 bool show_title = !data().mini || width() >= kMiniTabRendererAsNormalTabWidth; 955 bool show_title = !data().mini || width() >= kMiniTabRendererAsNormalTabWidth;
790 if (show_title) { 956 if (show_title) {
791 int title_left = favicon_bounds_.right() + kFaviconTitleSpacing; 957 int title_left = favicon_bounds_.right() + kFaviconTitleSpacing;
792 int title_width = lb.width() - title_left; 958 int title_width = lb.width() - title_left;
793 if (showing_media_indicator_) { 959 if (showing_media_indicator_) {
794 title_width = media_indicator_bounds_.x() - kViewSpacing - title_left; 960 title_width = media_indicator_button_->x() - kViewSpacing - title_left;
795 } else if (close_button_->visible()) { 961 } else if (close_button_->visible()) {
796 // Allow the title to overlay the close button's empty border padding. 962 // Allow the title to overlay the close button's empty border padding.
797 title_width = close_button_->x() + close_button_->GetInsets().left() - 963 title_width = close_button_->x() + close_button_->GetInsets().left() -
798 kViewSpacing - title_left; 964 kViewSpacing - title_left;
799 } 965 }
800 gfx::Rect rect(title_left, lb.y(), std::max(title_width, 0), lb.height()); 966 gfx::Rect rect(title_left, lb.y(), std::max(title_width, 0), lb.height());
801 const int title_height = title_->GetPreferredSize().height(); 967 const int title_height = title_->GetPreferredSize().height();
802 if (title_height > rect.height()) { 968 if (title_height > rect.height()) {
803 rect.set_y(lb.y() - (title_height - rect.height()) / 2); 969 rect.set_y(lb.y() - (title_height - rect.height()) / 2);
804 rect.set_height(title_height); 970 rect.set_height(title_height);
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
897 Tab* closest_tab = controller_->GetTabAt(this, event.location()); 1063 Tab* closest_tab = controller_->GetTabAt(this, event.location());
898 if (closest_tab) 1064 if (closest_tab)
899 controller_->CloseTab(closest_tab, CLOSE_TAB_FROM_MOUSE); 1065 controller_->CloseTab(closest_tab, CLOSE_TAB_FROM_MOUSE);
900 } 1066 }
901 } else if (event.IsOnlyLeftMouseButton() && !event.IsShiftDown() && 1067 } else if (event.IsOnlyLeftMouseButton() && !event.IsShiftDown() &&
902 !event.IsControlDown()) { 1068 !event.IsControlDown()) {
903 // If the tab was already selected mouse pressed doesn't change the 1069 // If the tab was already selected mouse pressed doesn't change the
904 // selection. Reset it now to handle the case where multiple tabs were 1070 // selection. Reset it now to handle the case where multiple tabs were
905 // selected. 1071 // selected.
906 controller_->SelectTab(this); 1072 controller_->SelectTab(this);
1073
1074 if (media_indicator_button_ && media_indicator_button_->visible() &&
1075 media_indicator_button_->bounds().Contains(event.location())) {
1076 content::RecordAction(UserMetricsAction("TabMediaIndicator_Clicked"));
1077 }
907 } 1078 }
908 } 1079 }
909 1080
910 void Tab::OnMouseCaptureLost() { 1081 void Tab::OnMouseCaptureLost() {
911 controller_->EndDrag(END_DRAG_CAPTURE_LOST); 1082 controller_->EndDrag(END_DRAG_CAPTURE_LOST);
912 } 1083 }
913 1084
914 void Tab::OnMouseEntered(const ui::MouseEvent& event) { 1085 void Tab::OnMouseEntered(const ui::MouseEvent& event) {
915 hover_controller_.Show(views::GlowHoverController::SUBTLE); 1086 hover_controller_.Show(views::GlowHoverController::SUBTLE);
916 } 1087 }
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
1013 const SkColor title_color = GetThemeProvider()->GetColor(IsSelected() ? 1184 const SkColor title_color = GetThemeProvider()->GetColor(IsSelected() ?
1014 ThemeProperties::COLOR_TAB_TEXT : 1185 ThemeProperties::COLOR_TAB_TEXT :
1015 ThemeProperties::COLOR_BACKGROUND_TAB_TEXT); 1186 ThemeProperties::COLOR_BACKGROUND_TAB_TEXT);
1016 title_->SetVisible(!data().mini || 1187 title_->SetVisible(!data().mini ||
1017 width() > kMiniTabRendererAsNormalTabWidth); 1188 width() > kMiniTabRendererAsNormalTabWidth);
1018 title_->SetEnabledColor(title_color); 1189 title_->SetEnabledColor(title_color);
1019 1190
1020 if (show_icon) 1191 if (show_icon)
1021 PaintIcon(canvas); 1192 PaintIcon(canvas);
1022 1193
1023 if (show_media_indicator)
1024 PaintMediaIndicator(canvas);
1025
1026 // If the close button color has changed, generate a new one. 1194 // If the close button color has changed, generate a new one.
1027 if (!close_button_color_ || title_color != close_button_color_) { 1195 if (!close_button_color_ || title_color != close_button_color_) {
1028 close_button_color_ = title_color; 1196 close_button_color_ = title_color;
1029 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 1197 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
1030 close_button_->SetBackground(close_button_color_, 1198 close_button_->SetBackground(close_button_color_,
1031 rb.GetImageSkiaNamed(IDR_CLOSE_1), 1199 rb.GetImageSkiaNamed(IDR_CLOSE_1),
1032 rb.GetImageSkiaNamed(IDR_CLOSE_1_MASK)); 1200 rb.GetImageSkiaNamed(IDR_CLOSE_1_MASK));
1033 } 1201 }
1034 } 1202 }
1035 1203
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after
1334 bounds, true, SkPaint()); 1502 bounds, true, SkPaint());
1335 } else if (!data().favicon.isNull()) { 1503 } else if (!data().favicon.isNull()) {
1336 // Paint the normal favicon. 1504 // Paint the normal favicon.
1337 DrawIconCenter(canvas, data().favicon, 0, 1505 DrawIconCenter(canvas, data().favicon, 0,
1338 data().favicon.width(), 1506 data().favicon.width(),
1339 data().favicon.height(), 1507 data().favicon.height(),
1340 bounds, true, SkPaint()); 1508 bounds, true, SkPaint());
1341 } 1509 }
1342 } 1510 }
1343 1511
1344 void Tab::PaintMediaIndicator(gfx::Canvas* canvas) {
1345 if (media_indicator_bounds_.IsEmpty() || !media_indicator_animation_)
1346 return;
1347
1348 gfx::Rect bounds = media_indicator_bounds_;
1349 bounds.set_x(GetMirroredXForRect(bounds));
1350
1351 SkPaint paint;
1352 paint.setAntiAlias(true);
1353 double opaqueness = media_indicator_animation_->GetCurrentValue();
1354 if (data_.media_state == TAB_MEDIA_STATE_NONE)
1355 opaqueness = 1.0 - opaqueness; // Fading out, not in.
1356 paint.setAlpha(opaqueness * SK_AlphaOPAQUE);
1357
1358 const gfx::ImageSkia& media_indicator_image =
1359 *(chrome::GetTabMediaIndicatorImage(animating_media_state_).
1360 ToImageSkia());
1361 DrawIconAtLocation(canvas, media_indicator_image, 0,
1362 bounds.x(), bounds.y(), media_indicator_image.width(),
1363 media_indicator_image.height(), true, paint);
1364 }
1365
1366 void Tab::AdvanceLoadingAnimation(TabRendererData::NetworkState old_state, 1512 void Tab::AdvanceLoadingAnimation(TabRendererData::NetworkState old_state,
1367 TabRendererData::NetworkState state) { 1513 TabRendererData::NetworkState state) {
1368 static bool initialized = false; 1514 static bool initialized = false;
1369 static int loading_animation_frame_count = 0; 1515 static int loading_animation_frame_count = 0;
1370 static int waiting_animation_frame_count = 0; 1516 static int waiting_animation_frame_count = 0;
1371 static int waiting_to_loading_frame_count_ratio = 0; 1517 static int waiting_to_loading_frame_count_ratio = 0;
1372 if (!initialized) { 1518 if (!initialized) {
1373 initialized = true; 1519 initialized = true;
1374 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 1520 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
1375 gfx::ImageSkia loading_animation(*rb.GetImageSkiaNamed(IDR_THROBBER)); 1521 gfx::ImageSkia loading_animation(*rb.GetImageSkiaNamed(IDR_THROBBER));
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
1432 if (available_width >= width_per_icon && 1578 if (available_width >= width_per_icon &&
1433 available_width < (width_per_icon + kPaddingBetweenIcons)) { 1579 available_width < (width_per_icon + kPaddingBetweenIcons)) {
1434 return 1; 1580 return 1;
1435 } 1581 }
1436 return available_width / (width_per_icon + kPaddingBetweenIcons); 1582 return available_width / (width_per_icon + kPaddingBetweenIcons);
1437 } 1583 }
1438 1584
1439 bool Tab::ShouldShowIcon() const { 1585 bool Tab::ShouldShowIcon() const {
1440 return chrome::ShouldTabShowFavicon( 1586 return chrome::ShouldTabShowFavicon(
1441 IconCapacity(), data().mini, IsActive(), data().show_icon, 1587 IconCapacity(), data().mini, IsActive(), data().show_icon,
1442 animating_media_state_); 1588 media_indicator_button_ ? media_indicator_button_->showing_media_state() :
1589 data_.media_state);
1443 } 1590 }
1444 1591
1445 bool Tab::ShouldShowMediaIndicator() const { 1592 bool Tab::ShouldShowMediaIndicator() const {
1446 return chrome::ShouldTabShowMediaIndicator( 1593 return chrome::ShouldTabShowMediaIndicator(
1447 IconCapacity(), data().mini, IsActive(), data().show_icon, 1594 IconCapacity(), data().mini, IsActive(), data().show_icon,
1448 animating_media_state_); 1595 media_indicator_button_ ? media_indicator_button_->showing_media_state() :
1596 data_.media_state);
1449 } 1597 }
1450 1598
1451 bool Tab::ShouldShowCloseBox() const { 1599 bool Tab::ShouldShowCloseBox() const {
1452 return chrome::ShouldTabShowCloseButton( 1600 return chrome::ShouldTabShowCloseButton(
1453 IconCapacity(), data().mini, IsActive()); 1601 IconCapacity(), data().mini, IsActive());
1454 } 1602 }
1455 1603
1456 double Tab::GetThrobValue() { 1604 double Tab::GetThrobValue() {
1457 const bool is_selected = IsSelected(); 1605 const bool is_selected = IsSelected();
1458 const double min = is_selected ? kSelectedTabOpacity : 0; 1606 const double min = is_selected ? kSelectedTabOpacity : 0;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1493 1641
1494 void Tab::StartCrashAnimation() { 1642 void Tab::StartCrashAnimation() {
1495 crash_icon_animation_.reset(new FaviconCrashAnimation(this)); 1643 crash_icon_animation_.reset(new FaviconCrashAnimation(this));
1496 crash_icon_animation_->Start(); 1644 crash_icon_animation_->Start();
1497 } 1645 }
1498 1646
1499 bool Tab::IsPerformingCrashAnimation() const { 1647 bool Tab::IsPerformingCrashAnimation() const {
1500 return crash_icon_animation_.get() && data_.IsCrashed(); 1648 return crash_icon_animation_.get() && data_.IsCrashed();
1501 } 1649 }
1502 1650
1503 void Tab::StartMediaIndicatorAnimation() {
1504 media_indicator_animation_ =
1505 chrome::CreateTabMediaIndicatorFadeAnimation(data_.media_state);
1506 media_indicator_animation_->set_delegate(this);
1507 media_indicator_animation_->Start();
1508 }
1509
1510 void Tab::ScheduleIconPaint() { 1651 void Tab::ScheduleIconPaint() {
1511 gfx::Rect bounds = favicon_bounds_; 1652 gfx::Rect bounds = favicon_bounds_;
1512 if (bounds.IsEmpty()) 1653 if (bounds.IsEmpty())
1513 return; 1654 return;
1514 1655
1515 // Extends the area to the bottom when sad_favicon is animating. 1656 // Extends the area to the bottom when sad_favicon is animating.
1516 if (IsPerformingCrashAnimation()) 1657 if (IsPerformingCrashAnimation())
1517 bounds.set_height(height() - bounds.y()); 1658 bounds.set_height(height() - bounds.y());
1518 bounds.set_x(GetMirroredXForRect(bounds)); 1659 bounds.set_x(GetMirroredXForRect(bounds));
1519 SchedulePaintInRect(bounds); 1660 SchedulePaintInRect(bounds);
(...skipping 19 matching lines...) Expand all
1539 *frame_id = 0; 1680 *frame_id = 0;
1540 } else if (data().incognito) { 1681 } else if (data().incognito) {
1541 *tab_id = IDR_THEME_TAB_BACKGROUND_INCOGNITO; 1682 *tab_id = IDR_THEME_TAB_BACKGROUND_INCOGNITO;
1542 *frame_id = IDR_THEME_FRAME_INCOGNITO; 1683 *frame_id = IDR_THEME_FRAME_INCOGNITO;
1543 } else { 1684 } else {
1544 *tab_id = IDR_THEME_TAB_BACKGROUND; 1685 *tab_id = IDR_THEME_TAB_BACKGROUND;
1545 *frame_id = IDR_THEME_FRAME; 1686 *frame_id = IDR_THEME_FRAME;
1546 } 1687 }
1547 } 1688 }
1548 1689
1690 Tab::MediaIndicatorButton* Tab::LazyGetMediaIndicatorButton() {
1691 if (!media_indicator_button_) {
1692 media_indicator_button_ = new MediaIndicatorButton(this);
1693 AddChildView(media_indicator_button_); // Takes ownership.
1694 }
1695 return media_indicator_button_;
1696 }
1697
1549 //////////////////////////////////////////////////////////////////////////////// 1698 ////////////////////////////////////////////////////////////////////////////////
1550 // Tab, private static: 1699 // Tab, private static:
1551 1700
1552 // static 1701 // static
1553 void Tab::InitTabResources() { 1702 void Tab::InitTabResources() {
1554 static bool initialized = false; 1703 static bool initialized = false;
1555 if (initialized) 1704 if (initialized)
1556 return; 1705 return;
1557 1706
1558 initialized = true; 1707 initialized = true;
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1603 const gfx::ImageSkia& image) { 1752 const gfx::ImageSkia& image) {
1604 DCHECK_NE(scale_factor, ui::SCALE_FACTOR_NONE); 1753 DCHECK_NE(scale_factor, ui::SCALE_FACTOR_NONE);
1605 ImageCacheEntry entry; 1754 ImageCacheEntry entry;
1606 entry.resource_id = resource_id; 1755 entry.resource_id = resource_id;
1607 entry.scale_factor = scale_factor; 1756 entry.scale_factor = scale_factor;
1608 entry.image = image; 1757 entry.image = image;
1609 image_cache_->push_front(entry); 1758 image_cache_->push_front(entry);
1610 if (image_cache_->size() > kMaxImageCacheSize) 1759 if (image_cache_->size() > kMaxImageCacheSize)
1611 image_cache_->pop_back(); 1760 image_cache_->pop_back();
1612 } 1761 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698