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 <stddef.h> | 7 #include <stddef.h> |
8 #include <limits> | 8 #include <limits> |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 | 109 |
110 // The minimum opacity (out of 1) when a tab (either active or inactive) is | 110 // The minimum opacity (out of 1) when a tab (either active or inactive) is |
111 // throbbing in the immersive mode light strip. | 111 // throbbing in the immersive mode light strip. |
112 const double kImmersiveTabMinThrobOpacity = 0.66; | 112 const double kImmersiveTabMinThrobOpacity = 0.66; |
113 | 113 |
114 // Number of steps in the immersive mode loading animation. | 114 // Number of steps in the immersive mode loading animation. |
115 const int kImmersiveLoadingStepCount = 32; | 115 const int kImmersiveLoadingStepCount = 32; |
116 | 116 |
117 const char kTabCloseButtonName[] = "TabCloseButton"; | 117 const char kTabCloseButtonName[] = "TabCloseButton"; |
118 | 118 |
| 119 // Desaturate favicon HSL shift values. |
| 120 const double kDesaturateHue = -1.0; |
| 121 const double kDesaturateSaturation = 0.0; |
| 122 const double kDesaturateLightness = 0.6; |
| 123 |
119 // Parameters for PaintTabBackgroundUsingParams(). | 124 // Parameters for PaintTabBackgroundUsingParams(). |
120 struct PaintBackgroundParams { | 125 struct PaintBackgroundParams { |
121 PaintBackgroundParams(bool is_active, | 126 PaintBackgroundParams(bool is_active, |
122 gfx::ImageSkia* fill_image_ptr, | 127 gfx::ImageSkia* fill_image_ptr, |
123 bool has_custom_image, | 128 bool has_custom_image, |
124 gfx::Rect rect, | 129 gfx::Rect rect, |
125 SkColor stroke_color, | 130 SkColor stroke_color, |
126 SkColor toolbar_color, | 131 SkColor toolbar_color, |
127 SkColor background_tab_color) | 132 SkColor background_tab_color) |
128 : is_active(is_active), | 133 : is_active(is_active), |
(...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
571 canvas->DrawImageInt(*stroke_images->image_l, 0, 0); | 576 canvas->DrawImageInt(*stroke_images->image_l, 0, 0); |
572 canvas->TileImageInt( | 577 canvas->TileImageInt( |
573 *stroke_images->image_c, stroke_images->l_width, 0, | 578 *stroke_images->image_c, stroke_images->l_width, 0, |
574 rect.width() - stroke_images->l_width - stroke_images->r_width, | 579 rect.width() - stroke_images->l_width - stroke_images->r_width, |
575 rect.height()); | 580 rect.height()); |
576 canvas->DrawImageInt(*stroke_images->image_r, | 581 canvas->DrawImageInt(*stroke_images->image_r, |
577 rect.width() - stroke_images->r_width, 0); | 582 rect.width() - stroke_images->r_width, 0); |
578 } | 583 } |
579 } | 584 } |
580 | 585 |
| 586 // Desaturates the favicon. Should only be used for when a tab encounters a |
| 587 // network error state. |
| 588 void PaintDesaturatedFavIcon(gfx::Canvas* canvas, |
| 589 gfx::ImageSkia& favicon, |
| 590 const gfx::Rect& bounds) { |
| 591 color_utils::HSL shift = {kDesaturateHue, |
| 592 kDesaturateSaturation, |
| 593 kDesaturateLightness}; |
| 594 gfx::ImageSkia desaturated_favicon = |
| 595 gfx::ImageSkiaOperations::CreateHSLShiftedImage(favicon, shift); |
| 596 if (!bounds.IsEmpty()) { |
| 597 canvas->DrawImageInt(desaturated_favicon, 0, 0, |
| 598 bounds.width(), bounds.height(), |
| 599 bounds.x(), bounds.y(), bounds.width(), |
| 600 bounds.height(), false); |
| 601 } else { |
| 602 canvas->DrawImageInt(desaturated_favicon, 0, 0); |
| 603 } |
| 604 } |
| 605 |
581 } // namespace | 606 } // namespace |
582 | 607 |
583 //////////////////////////////////////////////////////////////////////////////// | 608 //////////////////////////////////////////////////////////////////////////////// |
584 // FaviconCrashAnimation | 609 // FaviconCrashAnimation |
585 // | 610 // |
586 // A custom animation subclass to manage the favicon crash animation. | 611 // A custom animation subclass to manage the favicon crash animation. |
587 class Tab::FaviconCrashAnimation : public gfx::LinearAnimation, | 612 class Tab::FaviconCrashAnimation : public gfx::LinearAnimation, |
588 public gfx::AnimationDelegate { | 613 public gfx::AnimationDelegate { |
589 public: | 614 public: |
590 explicit FaviconCrashAnimation(Tab* target) | 615 explicit FaviconCrashAnimation(Tab* target) |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
752 loading_start_time_ = base::TimeTicks(); | 777 loading_start_time_ = base::TimeTicks(); |
753 waiting_state_ = gfx::ThrobberWaitingState(); | 778 waiting_state_ = gfx::ThrobberWaitingState(); |
754 } | 779 } |
755 | 780 |
756 bool Tab::ThrobberView::CanProcessEventsWithinSubtree() const { | 781 bool Tab::ThrobberView::CanProcessEventsWithinSubtree() const { |
757 return false; | 782 return false; |
758 } | 783 } |
759 | 784 |
760 void Tab::ThrobberView::OnPaint(gfx::Canvas* canvas) { | 785 void Tab::ThrobberView::OnPaint(gfx::Canvas* canvas) { |
761 const TabRendererData::NetworkState state = owner_->data().network_state; | 786 const TabRendererData::NetworkState state = owner_->data().network_state; |
762 if (state == TabRendererData::NETWORK_STATE_NONE) | 787 if (state == TabRendererData::NETWORK_STATE_NONE || |
| 788 state == TabRendererData::NETWORK_STATE_ERROR) |
763 return; | 789 return; |
764 | 790 |
765 const ui::ThemeProvider* tp = GetThemeProvider(); | 791 const ui::ThemeProvider* tp = GetThemeProvider(); |
766 const gfx::Rect bounds = GetLocalBounds(); | 792 const gfx::Rect bounds = GetLocalBounds(); |
767 if (state == TabRendererData::NETWORK_STATE_WAITING) { | 793 if (state == TabRendererData::NETWORK_STATE_WAITING) { |
768 if (waiting_start_time_ == base::TimeTicks()) | 794 if (waiting_start_time_ == base::TimeTicks()) |
769 waiting_start_time_ = base::TimeTicks::Now(); | 795 waiting_start_time_ = base::TimeTicks::Now(); |
770 | 796 |
771 waiting_state_.elapsed_time = base::TimeTicks::Now() - waiting_start_time_; | 797 waiting_state_.elapsed_time = base::TimeTicks::Now() - waiting_start_time_; |
772 gfx::PaintThrobberWaiting( | 798 gfx::PaintThrobberWaiting( |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
890 void Tab::AlertStateChanged() { | 916 void Tab::AlertStateChanged() { |
891 Layout(); | 917 Layout(); |
892 } | 918 } |
893 | 919 |
894 bool Tab::IsSelected() const { | 920 bool Tab::IsSelected() const { |
895 return controller_->IsTabSelected(this); | 921 return controller_->IsTabSelected(this); |
896 } | 922 } |
897 | 923 |
898 void Tab::SetData(const TabRendererData& data) { | 924 void Tab::SetData(const TabRendererData& data) { |
899 DCHECK(GetWidget()); | 925 DCHECK(GetWidget()); |
900 | |
901 if (data_.Equals(data)) | 926 if (data_.Equals(data)) |
902 return; | 927 return; |
903 | 928 |
904 TabRendererData old(data_); | 929 TabRendererData old(data_); |
905 UpdateLoadingAnimation(data.network_state); | 930 UpdateLoadingAnimation(data.network_state); |
906 data_ = data; | 931 data_ = data; |
907 | 932 |
908 base::string16 title = data_.title; | 933 base::string16 title = data_.title; |
909 if (title.empty()) { | 934 if (title.empty()) { |
910 title = data_.loading ? | 935 title = data_.loading ? |
(...skipping 21 matching lines...) Expand all Loading... |
932 showing_pinned_tab_title_changed_indicator_ = false; | 957 showing_pinned_tab_title_changed_indicator_ = false; |
933 | 958 |
934 DataChanged(old); | 959 DataChanged(old); |
935 | 960 |
936 Layout(); | 961 Layout(); |
937 SchedulePaint(); | 962 SchedulePaint(); |
938 } | 963 } |
939 | 964 |
940 void Tab::UpdateLoadingAnimation(TabRendererData::NetworkState state) { | 965 void Tab::UpdateLoadingAnimation(TabRendererData::NetworkState state) { |
941 if (state == data_.network_state && | 966 if (state == data_.network_state && |
942 state == TabRendererData::NETWORK_STATE_NONE) { | 967 (state == TabRendererData::NETWORK_STATE_NONE || |
943 // If the network state is none and hasn't changed, do nothing. Otherwise we | 968 state == TabRendererData::NETWORK_STATE_ERROR)) { |
944 // need to advance the animation frame. | 969 // If the network state is none or is an network error and hasn't changed, |
| 970 // do nothing. Otherwise we need to advance the animation frame. |
945 return; | 971 return; |
946 } | 972 } |
947 | 973 |
948 data_.network_state = state; | 974 data_.network_state = state; |
949 AdvanceLoadingAnimation(); | 975 AdvanceLoadingAnimation(); |
950 } | 976 } |
951 | 977 |
952 void Tab::StartPulse() { | 978 void Tab::StartPulse() { |
953 pulse_animation_->StartThrobbing(std::numeric_limits<int>::max()); | 979 pulse_animation_->StartThrobbing(std::numeric_limits<int>::max()); |
954 } | 980 } |
(...skipping 632 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1587 const gfx::Rect& favicon_draw_bounds) { | 1613 const gfx::Rect& favicon_draw_bounds) { |
1588 // The pinned tab title changed indicator consists of two parts: | 1614 // The pinned tab title changed indicator consists of two parts: |
1589 // . a clear (totally transparent) part over the bottom right (or left in rtl) | 1615 // . a clear (totally transparent) part over the bottom right (or left in rtl) |
1590 // of the favicon. This is done by drawing the favicon to a canvas, then | 1616 // of the favicon. This is done by drawing the favicon to a canvas, then |
1591 // drawing the clear part on top of the favicon. | 1617 // drawing the clear part on top of the favicon. |
1592 // . a circle in the bottom right (or left in rtl) of the favicon. | 1618 // . a circle in the bottom right (or left in rtl) of the favicon. |
1593 if (!favicon_.isNull()) { | 1619 if (!favicon_.isNull()) { |
1594 const float kIndicatorCropRadius = 4.5; | 1620 const float kIndicatorCropRadius = 4.5; |
1595 gfx::Canvas icon_canvas(gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize), | 1621 gfx::Canvas icon_canvas(gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize), |
1596 canvas->image_scale(), false); | 1622 canvas->image_scale(), false); |
1597 icon_canvas.DrawImageInt(favicon_, 0, 0); | 1623 |
| 1624 if (data().network_state == TabRendererData::NETWORK_STATE_ERROR) |
| 1625 PaintDesaturatedFavIcon(&icon_canvas, favicon_, gfx::Rect()); |
| 1626 else |
| 1627 icon_canvas.DrawImageInt(favicon_, 0, 0); |
| 1628 |
1598 SkPaint clear_paint; | 1629 SkPaint clear_paint; |
1599 clear_paint.setAntiAlias(true); | 1630 clear_paint.setAntiAlias(true); |
1600 clear_paint.setXfermodeMode(SkXfermode::kClear_Mode); | 1631 clear_paint.setXfermodeMode(SkXfermode::kClear_Mode); |
1601 const int circle_x = base::i18n::IsRTL() ? 0 : gfx::kFaviconSize; | 1632 const int circle_x = base::i18n::IsRTL() ? 0 : gfx::kFaviconSize; |
1602 icon_canvas.DrawCircle(gfx::PointF(circle_x, gfx::kFaviconSize), | 1633 icon_canvas.DrawCircle(gfx::PointF(circle_x, gfx::kFaviconSize), |
1603 kIndicatorCropRadius, clear_paint); | 1634 kIndicatorCropRadius, clear_paint); |
1604 canvas->DrawImageInt(gfx::ImageSkia(icon_canvas.ExtractImageRep()), 0, 0, | 1635 canvas->DrawImageInt(gfx::ImageSkia(icon_canvas.ExtractImageRep()), 0, 0, |
1605 favicon_draw_bounds.width(), | 1636 favicon_draw_bounds.width(), |
1606 favicon_draw_bounds.height(), favicon_draw_bounds.x(), | 1637 favicon_draw_bounds.height(), favicon_draw_bounds.x(), |
1607 favicon_draw_bounds.y(), favicon_draw_bounds.width(), | 1638 favicon_draw_bounds.y(), favicon_draw_bounds.width(), |
(...skipping 16 matching lines...) Expand all Loading... |
1624 | 1655 |
1625 void Tab::PaintIcon(gfx::Canvas* canvas) { | 1656 void Tab::PaintIcon(gfx::Canvas* canvas) { |
1626 gfx::Rect bounds = favicon_bounds_; | 1657 gfx::Rect bounds = favicon_bounds_; |
1627 bounds.set_x(GetMirroredXForRect(bounds)); | 1658 bounds.set_x(GetMirroredXForRect(bounds)); |
1628 bounds.Offset(0, favicon_hiding_offset_); | 1659 bounds.Offset(0, favicon_hiding_offset_); |
1629 bounds.Intersect(GetContentsBounds()); | 1660 bounds.Intersect(GetContentsBounds()); |
1630 if (bounds.IsEmpty()) | 1661 if (bounds.IsEmpty()) |
1631 return; | 1662 return; |
1632 | 1663 |
1633 // Throbber will do its own painting. | 1664 // Throbber will do its own painting. |
1634 if (data().network_state != TabRendererData::NETWORK_STATE_NONE) | 1665 if (data().network_state != TabRendererData::NETWORK_STATE_NONE && |
| 1666 data().network_state != TabRendererData::NETWORK_STATE_ERROR) |
1635 return; | 1667 return; |
1636 | 1668 |
1637 // Ensure that |favicon_| is created. | 1669 // Ensure that |favicon_| is created. |
1638 if (favicon_.isNull()) { | 1670 if (favicon_.isNull()) { |
1639 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); | 1671 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); |
1640 favicon_ = should_display_crashed_favicon_ | 1672 favicon_ = should_display_crashed_favicon_ |
1641 ? *rb->GetImageSkiaNamed(IDR_CRASH_SAD_FAVICON) | 1673 ? *rb->GetImageSkiaNamed(IDR_CRASH_SAD_FAVICON) |
1642 : data().favicon; | 1674 : data().favicon; |
1643 // Themify the icon if it's a chrome:// page or if it's the sadtab favicon. | 1675 // Themify the icon if it's a chrome:// page or if it's the sadtab favicon. |
1644 // This ensures chrome:// pages are visible over the tab background. This is | 1676 // This ensures chrome:// pages are visible over the tab background. This is |
1645 // similar to code in the bookmarks bar. | 1677 // similar to code in the bookmarks bar. |
1646 if (!favicon_.isNull() && | 1678 if (!favicon_.isNull() && |
1647 (should_display_crashed_favicon_ || | 1679 (should_display_crashed_favicon_ || |
1648 favicon_.BackedBySameObjectAs( | 1680 favicon_.BackedBySameObjectAs( |
1649 *rb->GetImageSkiaNamed(IDR_DEFAULT_FAVICON)) || | 1681 *rb->GetImageSkiaNamed(IDR_DEFAULT_FAVICON)) || |
1650 ShouldThemifyFaviconForUrl(data().url))) { | 1682 ShouldThemifyFaviconForUrl(data().url))) { |
1651 favicon_ = gfx::ImageSkiaOperations::CreateHSLShiftedImage( | 1683 favicon_ = gfx::ImageSkiaOperations::CreateHSLShiftedImage( |
1652 favicon_, GetThemeProvider()->GetTint(ThemeProperties::TINT_BUTTONS)); | 1684 favicon_, GetThemeProvider()->GetTint(ThemeProperties::TINT_BUTTONS)); |
1653 } | 1685 } |
1654 } | 1686 } |
1655 | 1687 |
1656 if (showing_pinned_tab_title_changed_indicator_ && | 1688 if (showing_pinned_tab_title_changed_indicator_ && |
1657 !should_display_crashed_favicon_) { | 1689 !should_display_crashed_favicon_) { |
1658 PaintPinnedTabTitleChangedIndicatorAndIcon(canvas, bounds); | 1690 PaintPinnedTabTitleChangedIndicatorAndIcon(canvas, bounds); |
1659 } else if (!favicon_.isNull()) { | 1691 } else if (!favicon_.isNull()) { |
1660 canvas->DrawImageInt(favicon_, 0, 0, bounds.width(), bounds.height(), | 1692 // Desaturate favicons of tabs with network errors. |
1661 bounds.x(), bounds.y(), bounds.width(), | 1693 if (data().network_state == TabRendererData::NETWORK_STATE_ERROR) { |
1662 bounds.height(), false); | 1694 PaintDesaturatedFavIcon(canvas, favicon_, bounds); |
| 1695 } else { |
| 1696 canvas->DrawImageInt(favicon_, 0, 0, bounds.width(), bounds.height(), |
| 1697 bounds.x(), bounds.y(), bounds.width(), |
| 1698 bounds.height(), false); |
| 1699 } |
1663 } | 1700 } |
1664 } | 1701 } |
1665 | 1702 |
1666 void Tab::AdvanceLoadingAnimation() { | 1703 void Tab::AdvanceLoadingAnimation() { |
1667 const TabRendererData::NetworkState state = data().network_state; | 1704 const TabRendererData::NetworkState state = data().network_state; |
1668 if (controller_->IsImmersiveStyle()) { | 1705 if (controller_->IsImmersiveStyle()) { |
1669 throbber_->SetVisible(false); | 1706 throbber_->SetVisible(false); |
1670 if (state == TabRendererData::NETWORK_STATE_WAITING) { | 1707 if (state == TabRendererData::NETWORK_STATE_WAITING) { |
1671 // Waiting steps backwards. | 1708 // Waiting steps backwards. |
1672 immersive_loading_step_ = | 1709 immersive_loading_step_ = |
1673 (immersive_loading_step_ - 1 + kImmersiveLoadingStepCount) % | 1710 (immersive_loading_step_ - 1 + kImmersiveLoadingStepCount) % |
1674 kImmersiveLoadingStepCount; | 1711 kImmersiveLoadingStepCount; |
1675 } else if (state == TabRendererData::NETWORK_STATE_LOADING) { | 1712 } else if (state == TabRendererData::NETWORK_STATE_LOADING) { |
1676 immersive_loading_step_ = | 1713 immersive_loading_step_ = |
1677 (immersive_loading_step_ + 1) % kImmersiveLoadingStepCount; | 1714 (immersive_loading_step_ + 1) % kImmersiveLoadingStepCount; |
1678 } else { | 1715 } else { |
1679 immersive_loading_step_ = 0; | 1716 immersive_loading_step_ = 0; |
1680 } | 1717 } |
1681 | 1718 |
1682 SchedulePaintInRect(GetImmersiveBarRect()); | 1719 SchedulePaintInRect(GetImmersiveBarRect()); |
1683 return; | 1720 return; |
1684 } | 1721 } |
1685 | 1722 |
1686 if (state == TabRendererData::NETWORK_STATE_NONE) { | 1723 if (state == TabRendererData::NETWORK_STATE_NONE || |
| 1724 state == TabRendererData::NETWORK_STATE_ERROR) { |
1687 throbber_->ResetStartTimes(); | 1725 throbber_->ResetStartTimes(); |
1688 throbber_->SetVisible(false); | 1726 throbber_->SetVisible(false); |
1689 ScheduleIconPaint(); | 1727 ScheduleIconPaint(); |
1690 return; | 1728 return; |
1691 } | 1729 } |
1692 | 1730 |
1693 // Since the throbber can animate for a long time, paint to a separate layer | 1731 // Since the throbber can animate for a long time, paint to a separate layer |
1694 // when possible to reduce repaint overhead. | 1732 // when possible to reduce repaint overhead. |
1695 const bool paint_to_layer = controller_->CanPaintThrobberToLayer(); | 1733 const bool paint_to_layer = controller_->CanPaintThrobberToLayer(); |
1696 if (paint_to_layer != !!throbber_->layer()) { | 1734 if (paint_to_layer != !!throbber_->layer()) { |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1821 gfx::Rect Tab::GetImmersiveBarRect() const { | 1859 gfx::Rect Tab::GetImmersiveBarRect() const { |
1822 // The main bar is as wide as the normal tab's horizontal top line. | 1860 // The main bar is as wide as the normal tab's horizontal top line. |
1823 // This top line of the tab extends a few pixels left and right of the | 1861 // This top line of the tab extends a few pixels left and right of the |
1824 // center image due to pixels in the rounded corner images. | 1862 // center image due to pixels in the rounded corner images. |
1825 const int kBarPadding = 1; | 1863 const int kBarPadding = 1; |
1826 int main_bar_left = g_active_images.l_width - kBarPadding; | 1864 int main_bar_left = g_active_images.l_width - kBarPadding; |
1827 int main_bar_right = width() - g_active_images.r_width + kBarPadding; | 1865 int main_bar_right = width() - g_active_images.r_width + kBarPadding; |
1828 return gfx::Rect( | 1866 return gfx::Rect( |
1829 main_bar_left, 0, main_bar_right - main_bar_left, kImmersiveBarHeight); | 1867 main_bar_left, 0, main_bar_right - main_bar_left, kImmersiveBarHeight); |
1830 } | 1868 } |
OLD | NEW |