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" |
(...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
458 closing_(false), | 458 closing_(false), |
459 dragging_(false), | 459 dragging_(false), |
460 favicon_hiding_offset_(0), | 460 favicon_hiding_offset_(0), |
461 loading_animation_frame_(0), | 461 loading_animation_frame_(0), |
462 immersive_loading_step_(0), | 462 immersive_loading_step_(0), |
463 should_display_crashed_favicon_(false), | 463 should_display_crashed_favicon_(false), |
464 theme_provider_(NULL), | 464 theme_provider_(NULL), |
465 tab_activated_with_last_gesture_begin_(false), | 465 tab_activated_with_last_gesture_begin_(false), |
466 hover_controller_(this), | 466 hover_controller_(this), |
467 showing_icon_(false), | 467 showing_icon_(false), |
| 468 showing_audio_indicator_(false), |
468 showing_close_button_(false), | 469 showing_close_button_(false), |
469 close_button_color_(0) { | 470 close_button_color_(0) { |
470 InitTabResources(); | 471 InitTabResources(); |
471 | 472 |
472 // So we get don't get enter/exit on children and don't prematurely stop the | 473 // So we get don't get enter/exit on children and don't prematurely stop the |
473 // hover. | 474 // hover. |
474 set_notify_enter_exit_on_child(true); | 475 set_notify_enter_exit_on_child(true); |
475 | 476 |
476 set_id(VIEW_ID_TAB); | 477 set_id(VIEW_ID_TAB); |
477 | 478 |
478 // Add the Close Button. | 479 // Add the Close Button. |
479 close_button_ = new TabCloseButton(this); | 480 close_button_ = new TabCloseButton(this); |
480 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 481 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
481 close_button_->SetImage(views::CustomButton::STATE_NORMAL, | 482 close_button_->SetImage(views::CustomButton::STATE_NORMAL, |
482 rb.GetImageSkiaNamed(IDR_CLOSE_1)); | 483 rb.GetImageSkiaNamed(IDR_CLOSE_1)); |
483 close_button_->SetImage(views::CustomButton::STATE_HOVERED, | 484 close_button_->SetImage(views::CustomButton::STATE_HOVERED, |
484 rb.GetImageSkiaNamed(IDR_CLOSE_1_H)); | 485 rb.GetImageSkiaNamed(IDR_CLOSE_1_H)); |
485 close_button_->SetImage(views::CustomButton::STATE_PRESSED, | 486 close_button_->SetImage(views::CustomButton::STATE_PRESSED, |
486 rb.GetImageSkiaNamed(IDR_CLOSE_1_P)); | 487 rb.GetImageSkiaNamed(IDR_CLOSE_1_P)); |
487 close_button_->SetAccessibleName( | 488 close_button_->SetAccessibleName( |
488 l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE)); | 489 l10n_util::GetStringUTF16(IDS_ACCNAME_CLOSE)); |
489 // Disable animation so that the red danger sign shows up immediately | 490 // Disable animation so that the red danger sign shows up immediately |
490 // to help avoid mis-clicks. | 491 // to help avoid mis-clicks. |
491 close_button_->SetAnimationDuration(0); | 492 close_button_->SetAnimationDuration(0); |
492 AddChildView(close_button_); | 493 AddChildView(close_button_); |
493 | 494 |
494 set_context_menu_controller(this); | 495 set_context_menu_controller(this); |
495 | |
496 tab_audio_indicator_.reset(new TabAudioIndicator(this)); | |
497 } | 496 } |
498 | 497 |
499 Tab::~Tab() { | 498 Tab::~Tab() { |
500 } | 499 } |
501 | 500 |
502 void Tab::set_animation_container(gfx::AnimationContainer* container) { | 501 void Tab::set_animation_container(gfx::AnimationContainer* container) { |
503 animation_container_ = container; | 502 animation_container_ = container; |
504 hover_controller_.SetAnimationContainer(container); | 503 hover_controller_.SetAnimationContainer(container); |
505 tab_audio_indicator_->SetAnimationContainer(container); | |
506 } | 504 } |
507 | 505 |
508 bool Tab::IsActive() const { | 506 bool Tab::IsActive() const { |
509 return controller() ? controller()->IsActiveTab(this) : true; | 507 return controller() ? controller()->IsActiveTab(this) : true; |
510 } | 508 } |
511 | 509 |
512 bool Tab::IsSelected() const { | 510 bool Tab::IsSelected() const { |
513 return controller() ? controller()->IsTabSelected(this) : true; | 511 return controller() ? controller()->IsTabSelected(this) : true; |
514 } | 512 } |
515 | 513 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
549 ResetCrashedFavicon(); | 547 ResetCrashedFavicon(); |
550 } | 548 } |
551 | 549 |
552 if (old.mini != data_.mini) { | 550 if (old.mini != data_.mini) { |
553 if (tab_animation_.get() && tab_animation_->is_animating()) { | 551 if (tab_animation_.get() && tab_animation_->is_animating()) { |
554 tab_animation_->Stop(); | 552 tab_animation_->Stop(); |
555 tab_animation_.reset(NULL); | 553 tab_animation_.reset(NULL); |
556 } | 554 } |
557 } | 555 } |
558 | 556 |
559 tab_audio_indicator_->SetIsPlayingAudio(data_.AudioActive()); | |
560 | |
561 DataChanged(old); | 557 DataChanged(old); |
562 | 558 |
563 Layout(); | 559 Layout(); |
564 SchedulePaint(); | 560 SchedulePaint(); |
565 } | 561 } |
566 | 562 |
567 void Tab::UpdateLoadingAnimation(TabRendererData::NetworkState state) { | 563 void Tab::UpdateLoadingAnimation(TabRendererData::NetworkState state) { |
568 if (state == data_.network_state && | 564 if (state == data_.network_state && |
569 state == TabRendererData::NETWORK_STATE_NONE) { | 565 state == TabRendererData::NETWORK_STATE_NONE) { |
570 // If the network state is none and hasn't changed, do nothing. Otherwise we | 566 // If the network state is none and hasn't changed, do nothing. Otherwise we |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
672 int Tab::GetMiniWidth() { | 668 int Tab::GetMiniWidth() { |
673 return browser_defaults::kMiniTabWidth; | 669 return browser_defaults::kMiniTabWidth; |
674 } | 670 } |
675 | 671 |
676 // static | 672 // static |
677 int Tab::GetImmersiveHeight() { | 673 int Tab::GetImmersiveHeight() { |
678 return kImmersiveTabHeight; | 674 return kImmersiveTabHeight; |
679 } | 675 } |
680 | 676 |
681 //////////////////////////////////////////////////////////////////////////////// | 677 //////////////////////////////////////////////////////////////////////////////// |
682 // Tab, TabAudioIndicator::Delegate overrides: | |
683 | |
684 void Tab::ScheduleAudioIndicatorPaint() { | |
685 // No need to schedule a paint if another animation is active. The other | |
686 // animation will do its own scheduling. | |
687 if (!icon_animation_) | |
688 ScheduleIconPaint(); | |
689 } | |
690 | |
691 //////////////////////////////////////////////////////////////////////////////// | |
692 // Tab, AnimationDelegate overrides: | 678 // Tab, AnimationDelegate overrides: |
693 | 679 |
694 void Tab::AnimationProgressed(const gfx::Animation* animation) { | 680 void Tab::AnimationProgressed(const gfx::Animation* animation) { |
695 // Ignore if the pulse animation is being performed on active tab because | 681 // Ignore if the pulse animation is being performed on active tab because |
696 // it repaints the same image. See |Tab::PaintTabBackground()|. | 682 // it repaints the same image. See |Tab::PaintTabBackground()|. |
697 if (animation == tab_animation_.get() && IsActive()) | 683 if (animation == tab_animation_.get() && IsActive()) |
698 return; | 684 return; |
699 SchedulePaint(); | 685 SchedulePaint(); |
700 } | 686 } |
701 | 687 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
774 content_height = std::max(content_height, close_button_size.height()); | 760 content_height = std::max(content_height, close_button_size.height()); |
775 | 761 |
776 // Size the Favicon. | 762 // Size the Favicon. |
777 showing_icon_ = ShouldShowIcon(); | 763 showing_icon_ = ShouldShowIcon(); |
778 if (showing_icon_) { | 764 if (showing_icon_) { |
779 // Use the size of the favicon as apps use a bigger favicon size. | 765 // Use the size of the favicon as apps use a bigger favicon size. |
780 int favicon_top = top_padding() + content_height / 2 - tab_icon_size() / 2; | 766 int favicon_top = top_padding() + content_height / 2 - tab_icon_size() / 2; |
781 int favicon_left = lb.x(); | 767 int favicon_left = lb.x(); |
782 favicon_bounds_.SetRect(favicon_left, favicon_top, | 768 favicon_bounds_.SetRect(favicon_left, favicon_top, |
783 tab_icon_size(), tab_icon_size()); | 769 tab_icon_size(), tab_icon_size()); |
784 if (data().mini && width() < kMiniTabRendererAsNormalTabWidth) { | 770 MaybeAdjustLeftForMiniTab(&favicon_bounds_); |
785 // Adjust the location of the favicon when transitioning from a normal | |
786 // tab to a mini-tab. | |
787 int mini_delta = kMiniTabRendererAsNormalTabWidth - GetMiniWidth(); | |
788 int ideal_delta = width() - GetMiniWidth(); | |
789 if (ideal_delta < mini_delta) { | |
790 int ideal_x = (GetMiniWidth() - tab_icon_size()) / 2; | |
791 int x = favicon_bounds_.x() + static_cast<int>( | |
792 (1 - static_cast<float>(ideal_delta) / | |
793 static_cast<float>(mini_delta)) * | |
794 (ideal_x - favicon_bounds_.x())); | |
795 favicon_bounds_.set_x(x); | |
796 } | |
797 } | |
798 } else { | 771 } else { |
799 favicon_bounds_.SetRect(lb.x(), lb.y(), 0, 0); | 772 favicon_bounds_.SetRect(lb.x(), lb.y(), 0, 0); |
800 } | 773 } |
801 | 774 |
802 // Size the Close button. | 775 // Size the Close button. |
803 showing_close_button_ = ShouldShowCloseBox(); | 776 showing_close_button_ = ShouldShowCloseBox(); |
804 const bool is_host_desktop_type_ash = | 777 const bool is_host_desktop_type_ash = |
805 GetHostDesktopType(this) == chrome::HOST_DESKTOP_TYPE_ASH; | 778 GetHostDesktopType(this) == chrome::HOST_DESKTOP_TYPE_ASH; |
806 if (showing_close_button_) { | 779 if (showing_close_button_) { |
807 const int close_button_vert_fuzz = is_host_desktop_type_ash ? | 780 const int close_button_vert_fuzz = is_host_desktop_type_ash ? |
(...skipping 16 matching lines...) Expand all Loading... |
824 close_button_->set_border(views::Border::CreateEmptyBorder(top_border, | 797 close_button_->set_border(views::Border::CreateEmptyBorder(top_border, |
825 left_border, bottom_border, right_border)); | 798 left_border, bottom_border, right_border)); |
826 close_button_->SetPosition(gfx::Point(lb.width(), 0)); | 799 close_button_->SetPosition(gfx::Point(lb.width(), 0)); |
827 close_button_->SizeToPreferredSize(); | 800 close_button_->SizeToPreferredSize(); |
828 close_button_->SetVisible(true); | 801 close_button_->SetVisible(true); |
829 } else { | 802 } else { |
830 close_button_->SetBounds(0, 0, 0, 0); | 803 close_button_->SetBounds(0, 0, 0, 0); |
831 close_button_->SetVisible(false); | 804 close_button_->SetVisible(false); |
832 } | 805 } |
833 | 806 |
| 807 showing_audio_indicator_ = ShouldShowAudioIndicator(); |
| 808 if (showing_audio_indicator_) { |
| 809 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| 810 gfx::ImageSkia audio_indicator_image( |
| 811 *rb.GetImageSkiaNamed(IDR_TAB_AUDIO_INDICATOR)); |
| 812 const int top = |
| 813 top_padding() + (content_height - audio_indicator_image.height()) / 2; |
| 814 const int right = showing_close_button_ ? |
| 815 close_button_->x() + close_button_->GetInsets().left() : lb.right(); |
| 816 const int left = std::max(lb.x(), right - audio_indicator_image.width()); |
| 817 audio_indicator_bounds_.SetRect(left, top, |
| 818 tab_icon_size(), tab_icon_size()); |
| 819 MaybeAdjustLeftForMiniTab(&audio_indicator_bounds_); |
| 820 } else { |
| 821 audio_indicator_bounds_.SetRect(lb.x(), lb.y(), 0, 0); |
| 822 } |
| 823 |
834 const int title_text_offset = is_host_desktop_type_ash ? | 824 const int title_text_offset = is_host_desktop_type_ash ? |
835 kTitleTextOffsetYAsh : kTitleTextOffsetY; | 825 kTitleTextOffsetYAsh : kTitleTextOffsetY; |
836 int title_left = favicon_bounds_.right() + kFaviconTitleSpacing; | 826 int title_left = favicon_bounds_.right() + kFaviconTitleSpacing; |
837 int title_top = top_padding() + title_text_offset + | 827 int title_top = top_padding() + title_text_offset + |
838 (content_height - font_height_) / 2; | 828 (content_height - font_height_) / 2; |
839 // Size the Title text to fill the remaining space. | 829 // Size the Title text to fill the remaining space. |
840 if (!data().mini || width() >= kMiniTabRendererAsNormalTabWidth) { | 830 if (!data().mini || width() >= kMiniTabRendererAsNormalTabWidth) { |
841 // If the user has big fonts, the title will appear rendered too far down | 831 // If the user has big fonts, the title will appear rendered too far down |
842 // on the y-axis if we use the regular top padding, so we need to adjust it | 832 // on the y-axis if we use the regular top padding, so we need to adjust it |
843 // so that the text appears centered. | 833 // so that the text appears centered. |
844 gfx::Size minimum_size = GetMinimumUnselectedSize(); | 834 gfx::Size minimum_size = GetMinimumUnselectedSize(); |
845 int text_height = title_top + font_height_ + bottom_padding(); | 835 int text_height = title_top + font_height_ + bottom_padding(); |
846 if (text_height > minimum_size.height()) | 836 if (text_height > minimum_size.height()) |
847 title_top -= (text_height - minimum_size.height()) / 2; | 837 title_top -= (text_height - minimum_size.height()) / 2; |
848 | 838 |
849 int title_width; | 839 int title_width; |
850 if (close_button_->visible()) { | 840 if (showing_audio_indicator_) { |
| 841 title_width = audio_indicator_bounds_.x() - kTitleCloseButtonSpacing - |
| 842 title_left; |
| 843 } else if (close_button_->visible()) { |
851 // The close button has an empty border with some padding (see details | 844 // The close button has an empty border with some padding (see details |
852 // above where the close-button's bounds is set). Allow the title to | 845 // above where the close-button's bounds is set). Allow the title to |
853 // overlap the empty padding. | 846 // overlap the empty padding. |
854 title_width = std::max(close_button_->x() + | 847 title_width = close_button_->x() + close_button_->GetInsets().left() - |
855 close_button_->GetInsets().left() - | 848 kTitleCloseButtonSpacing - title_left; |
856 kTitleCloseButtonSpacing - title_left, 0); | |
857 } else { | 849 } else { |
858 title_width = std::max(lb.width() - title_left, 0); | 850 title_width = lb.width() - title_left; |
859 } | 851 } |
| 852 title_width = std::max(title_width, 0); |
860 title_bounds_.SetRect(title_left, title_top, title_width, font_height_); | 853 title_bounds_.SetRect(title_left, title_top, title_width, font_height_); |
861 } else { | 854 } else { |
862 title_bounds_.SetRect(title_left, title_top, 0, 0); | 855 title_bounds_.SetRect(title_left, title_top, 0, 0); |
863 } | 856 } |
864 | 857 |
865 // Certain UI elements within the Tab (the favicon, etc.) are not represented | 858 // Certain UI elements within the Tab (the favicon, etc.) are not represented |
866 // as child Views (which is the preferred method). Instead, these UI elements | 859 // as child Views (which is the preferred method). Instead, these UI elements |
867 // are drawn directly on the canvas from within Tab::OnPaint(). The Tab's | 860 // are drawn directly on the canvas from within Tab::OnPaint(). The Tab's |
868 // child Views (for example, the Tab's close button which is a views::Button | 861 // child Views (for example, the Tab's close button which is a views::Button |
869 // instance) are automatically mirrored by the mirroring infrastructure in | 862 // instance) are automatically mirrored by the mirroring infrastructure in |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1070 // Tab, private | 1063 // Tab, private |
1071 | 1064 |
1072 const gfx::Rect& Tab::GetTitleBounds() const { | 1065 const gfx::Rect& Tab::GetTitleBounds() const { |
1073 return title_bounds_; | 1066 return title_bounds_; |
1074 } | 1067 } |
1075 | 1068 |
1076 const gfx::Rect& Tab::GetIconBounds() const { | 1069 const gfx::Rect& Tab::GetIconBounds() const { |
1077 return favicon_bounds_; | 1070 return favicon_bounds_; |
1078 } | 1071 } |
1079 | 1072 |
| 1073 void Tab::MaybeAdjustLeftForMiniTab(gfx::Rect* bounds) const { |
| 1074 if (!data().mini || width() >= kMiniTabRendererAsNormalTabWidth) |
| 1075 return; |
| 1076 const int mini_delta = kMiniTabRendererAsNormalTabWidth - GetMiniWidth(); |
| 1077 const int ideal_delta = width() - GetMiniWidth(); |
| 1078 const int ideal_x = (GetMiniWidth() - bounds->width()) / 2; |
| 1079 bounds->set_x(bounds->x() + static_cast<int>( |
| 1080 (1 - static_cast<float>(ideal_delta) / static_cast<float>(mini_delta)) * |
| 1081 (ideal_x - bounds->x()))); |
| 1082 } |
| 1083 |
1080 void Tab::DataChanged(const TabRendererData& old) { | 1084 void Tab::DataChanged(const TabRendererData& old) { |
1081 if (data().blocked == old.blocked) | 1085 if (data().blocked == old.blocked) |
1082 return; | 1086 return; |
1083 | 1087 |
1084 if (data().blocked) | 1088 if (data().blocked) |
1085 StartPulse(); | 1089 StartPulse(); |
1086 else | 1090 else |
1087 StopPulse(); | 1091 StopPulse(); |
1088 } | 1092 } |
1089 | 1093 |
1090 void Tab::PaintTab(gfx::Canvas* canvas) { | 1094 void Tab::PaintTab(gfx::Canvas* canvas) { |
1091 // See if the model changes whether the icons should be painted. | 1095 // See if the model changes whether the icons should be painted. |
1092 const bool show_icon = ShouldShowIcon(); | 1096 const bool show_icon = ShouldShowIcon(); |
| 1097 const bool show_audio_indicator = ShouldShowAudioIndicator(); |
1093 const bool show_close_button = ShouldShowCloseBox(); | 1098 const bool show_close_button = ShouldShowCloseBox(); |
1094 if (show_icon != showing_icon_ || show_close_button != showing_close_button_) | 1099 if (show_icon != showing_icon_ || |
| 1100 show_audio_indicator != showing_audio_indicator_ || |
| 1101 show_close_button != showing_close_button_) { |
1095 Layout(); | 1102 Layout(); |
| 1103 } |
1096 | 1104 |
1097 PaintTabBackground(canvas); | 1105 PaintTabBackground(canvas); |
1098 | 1106 |
1099 SkColor title_color = GetThemeProvider()-> | 1107 SkColor title_color = GetThemeProvider()-> |
1100 GetColor(IsSelected() ? | 1108 GetColor(IsSelected() ? |
1101 ThemeProperties::COLOR_TAB_TEXT : | 1109 ThemeProperties::COLOR_TAB_TEXT : |
1102 ThemeProperties::COLOR_BACKGROUND_TAB_TEXT); | 1110 ThemeProperties::COLOR_BACKGROUND_TAB_TEXT); |
1103 | 1111 |
1104 if (!data().mini || width() > kMiniTabRendererAsNormalTabWidth) | 1112 if (!data().mini || width() > kMiniTabRendererAsNormalTabWidth) |
1105 PaintTitle(canvas, title_color); | 1113 PaintTitle(canvas, title_color); |
1106 | 1114 |
1107 if (show_icon) | 1115 if (show_icon) |
1108 PaintIcon(canvas); | 1116 PaintIcon(canvas); |
1109 | 1117 |
| 1118 if (show_audio_indicator) |
| 1119 PaintAudioIndicator(canvas); |
| 1120 |
1110 // If the close button color has changed, generate a new one. | 1121 // If the close button color has changed, generate a new one. |
1111 if (!close_button_color_ || title_color != close_button_color_) { | 1122 if (!close_button_color_ || title_color != close_button_color_) { |
1112 close_button_color_ = title_color; | 1123 close_button_color_ = title_color; |
1113 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 1124 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
1114 close_button_->SetBackground(close_button_color_, | 1125 close_button_->SetBackground(close_button_color_, |
1115 rb.GetImageSkiaNamed(IDR_CLOSE_1), | 1126 rb.GetImageSkiaNamed(IDR_CLOSE_1), |
1116 rb.GetImageSkiaNamed(IDR_CLOSE_1_MASK)); | 1127 rb.GetImageSkiaNamed(IDR_CLOSE_1_MASK)); |
1117 } | 1128 } |
1118 } | 1129 } |
1119 | 1130 |
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1450 resized_icon.height(), | 1461 resized_icon.height(), |
1451 resized_bounds, true, SkPaint()); | 1462 resized_bounds, true, SkPaint()); |
1452 | 1463 |
1453 ui::ThemeProvider* tp = GetThemeProvider(); | 1464 ui::ThemeProvider* tp = GetThemeProvider(); |
1454 gfx::ImageSkia projection_screen( | 1465 gfx::ImageSkia projection_screen( |
1455 *tp->GetImageSkiaNamed(IDR_TAB_CAPTURE)); | 1466 *tp->GetImageSkiaNamed(IDR_TAB_CAPTURE)); |
1456 DrawIconCenter(canvas, projection_screen, 0, | 1467 DrawIconCenter(canvas, projection_screen, 0, |
1457 data().favicon.width(), | 1468 data().favicon.width(), |
1458 data().favicon.height(), | 1469 data().favicon.height(), |
1459 bounds, true, SkPaint()); | 1470 bounds, true, SkPaint()); |
1460 } else if (!icon_animation_ && tab_audio_indicator_->IsAnimating()) { | |
1461 // Draw the audio indicator UI only if no other icon animation is | |
1462 // active. | |
1463 if (!icon_animation_ && tab_audio_indicator_->IsAnimating()) { | |
1464 tab_audio_indicator_->set_favicon(data().favicon); | |
1465 tab_audio_indicator_->Paint(canvas, bounds); | |
1466 } | |
1467 } else { | 1471 } else { |
1468 DrawIconCenter(canvas, data().favicon, 0, | 1472 DrawIconCenter(canvas, data().favicon, 0, |
1469 data().favicon.width(), | 1473 data().favicon.width(), |
1470 data().favicon.height(), | 1474 data().favicon.height(), |
1471 bounds, true, SkPaint()); | 1475 bounds, true, SkPaint()); |
1472 } | 1476 } |
1473 } | 1477 } |
1474 } | 1478 } |
1475 canvas->Restore(); | 1479 canvas->Restore(); |
1476 | 1480 |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1566 | 1570 |
1567 // Draw the recording icon. | 1571 // Draw the recording icon. |
1568 DrawIconBottomRight(canvas, recording_dot, 0, | 1572 DrawIconBottomRight(canvas, recording_dot, 0, |
1569 recording_dot.width(), recording_dot.height(), | 1573 recording_dot.width(), recording_dot.height(), |
1570 bounds, false, paint); | 1574 bounds, false, paint); |
1571 } else { | 1575 } else { |
1572 NOTREACHED(); | 1576 NOTREACHED(); |
1573 } | 1577 } |
1574 } | 1578 } |
1575 | 1579 |
| 1580 void Tab::PaintAudioIndicator(gfx::Canvas* canvas) { |
| 1581 if (audio_indicator_bounds_.IsEmpty()) |
| 1582 return; |
| 1583 |
| 1584 gfx::Rect bounds = audio_indicator_bounds_; |
| 1585 bounds.set_x(GetMirroredXForRect(bounds)); |
| 1586 |
| 1587 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| 1588 const gfx::ImageSkia audio_indicator_image( |
| 1589 *rb.GetImageSkiaNamed(IDR_TAB_AUDIO_INDICATOR)); |
| 1590 DrawIconAtLocation(canvas, audio_indicator_image, 0, |
| 1591 bounds.x(), bounds.y(), audio_indicator_image.width(), |
| 1592 audio_indicator_image.height(), true, SkPaint()); |
| 1593 } |
| 1594 |
1576 void Tab::PaintTitle(gfx::Canvas* canvas, SkColor title_color) { | 1595 void Tab::PaintTitle(gfx::Canvas* canvas, SkColor title_color) { |
1577 // Paint the Title. | 1596 // Paint the Title. |
1578 const gfx::Rect& title_bounds = GetTitleBounds(); | 1597 const gfx::Rect& title_bounds = GetTitleBounds(); |
1579 string16 title = data().title; | 1598 string16 title = data().title; |
1580 | 1599 |
1581 if (title.empty()) { | 1600 if (title.empty()) { |
1582 title = data().loading ? | 1601 title = data().loading ? |
1583 l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE) : | 1602 l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE) : |
1584 CoreTabHelper::GetDefaultTitle(); | 1603 CoreTabHelper::GetDefaultTitle(); |
1585 } else { | 1604 } else { |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1645 } | 1664 } |
1646 if (controller() && controller()->IsImmersiveStyle()) | 1665 if (controller() && controller()->IsImmersiveStyle()) |
1647 SchedulePaintInRect(GetImmersiveBarRect()); | 1666 SchedulePaintInRect(GetImmersiveBarRect()); |
1648 else | 1667 else |
1649 ScheduleIconPaint(); | 1668 ScheduleIconPaint(); |
1650 } | 1669 } |
1651 | 1670 |
1652 int Tab::IconCapacity() const { | 1671 int Tab::IconCapacity() const { |
1653 if (height() < GetMinimumUnselectedSize().height()) | 1672 if (height() < GetMinimumUnselectedSize().height()) |
1654 return 0; | 1673 return 0; |
1655 return (width() - left_padding() - right_padding()) / tab_icon_size(); | 1674 const int kPaddingBetweenIcons = 2; |
| 1675 return (width() - left_padding() - right_padding()) / |
| 1676 (tab_icon_size() + kPaddingBetweenIcons); |
1656 } | 1677 } |
1657 | 1678 |
1658 bool Tab::ShouldShowIcon() const { | 1679 bool Tab::ShouldShowIcon() const { |
| 1680 if (!data().show_icon) |
| 1681 return false; |
| 1682 const bool should_show_audio_indicator = ShouldShowAudioIndicator(); |
| 1683 if (data().mini && height() >= GetMinimumUnselectedSize().height()) { |
| 1684 // Audio indicator always takes precendence over the favicon for mini tabs. |
| 1685 return !should_show_audio_indicator; |
| 1686 } |
| 1687 int required_capacity = should_show_audio_indicator ? 2 : 1; |
| 1688 if (IsActive()) { |
| 1689 // Active tabs give priority to the close button, then the audio indicator, |
| 1690 // then the favicon. |
| 1691 ++required_capacity; |
| 1692 } else { |
| 1693 // Non-active tabs give priority to the audio indicator, then the favicon, |
| 1694 // and finally the close button. |
| 1695 } |
| 1696 return IconCapacity() >= required_capacity; |
| 1697 } |
| 1698 |
| 1699 bool Tab::ShouldShowAudioIndicator() const { |
| 1700 // Note: If the capture indicator is active, then do not show the audio |
| 1701 // indicator. This allows the favicon "throbber" animation to be shown in |
| 1702 // small-width situations. |
| 1703 if (!data().AudioActive() || data().CaptureActive()) |
| 1704 return false; |
1659 if (data().mini && height() >= GetMinimumUnselectedSize().height()) | 1705 if (data().mini && height() >= GetMinimumUnselectedSize().height()) |
1660 return true; | 1706 return true; |
1661 if (!data().show_icon) { | 1707 if (IsActive()) { |
1662 return false; | 1708 // The active tab clips the audio indicator before the close button. |
1663 } else if (IsActive()) { | |
1664 // The active tab clips favicon before close button. | |
1665 return IconCapacity() >= 2; | 1709 return IconCapacity() >= 2; |
1666 } | 1710 } |
1667 // Non-selected tabs clip close button before favicon. | 1711 // Non-active tabs clip close button before the audio indicator. |
1668 return IconCapacity() >= 1; | 1712 return IconCapacity() >= 1; |
1669 } | 1713 } |
1670 | 1714 |
1671 bool Tab::ShouldShowCloseBox() const { | 1715 bool Tab::ShouldShowCloseBox() const { |
1672 // The active tab never clips close button. | 1716 // The active tab never clips close button. |
1673 return !data().mini && (IsActive() || IconCapacity() >= 3); | 1717 return !data().mini && (IsActive() || IconCapacity() >= 3); |
1674 } | 1718 } |
1675 | 1719 |
1676 double Tab::GetThrobValue() { | 1720 double Tab::GetThrobValue() { |
1677 bool is_selected = IsSelected(); | 1721 bool is_selected = IsSelected(); |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1834 const gfx::ImageSkia& image) { | 1878 const gfx::ImageSkia& image) { |
1835 DCHECK_NE(scale_factor, ui::SCALE_FACTOR_NONE); | 1879 DCHECK_NE(scale_factor, ui::SCALE_FACTOR_NONE); |
1836 ImageCacheEntry entry; | 1880 ImageCacheEntry entry; |
1837 entry.resource_id = resource_id; | 1881 entry.resource_id = resource_id; |
1838 entry.scale_factor = scale_factor; | 1882 entry.scale_factor = scale_factor; |
1839 entry.image = image; | 1883 entry.image = image; |
1840 image_cache_->push_front(entry); | 1884 image_cache_->push_front(entry); |
1841 if (image_cache_->size() > kMaxImageCacheSize) | 1885 if (image_cache_->size() > kMaxImageCacheSize) |
1842 image_cache_->pop_back(); | 1886 image_cache_->pop_back(); |
1843 } | 1887 } |
OLD | NEW |