OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |