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

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

Issue 2321833002: [Mac] Desaturate the Favicon for Network Errors (Closed)
Patch Set: Fix for Views Created 4 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 <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
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
124 //////////////////////////////////////////////////////////////////////////////// 119 ////////////////////////////////////////////////////////////////////////////////
125 // ImageCacheEntryMetadata 120 // ImageCacheEntryMetadata
126 // 121 //
127 // All metadata necessary to uniquely identify a cached image. 122 // All metadata necessary to uniquely identify a cached image.
128 struct ImageCacheEntryMetadata { 123 struct ImageCacheEntryMetadata {
129 ImageCacheEntryMetadata(int resource_id, 124 ImageCacheEntryMetadata(int resource_id,
130 SkColor fill_color, 125 SkColor fill_color,
131 SkColor stroke_color, 126 SkColor stroke_color,
132 bool use_fill_and_stroke_images, 127 bool use_fill_and_stroke_images,
133 float scale_factor, 128 float scale_factor,
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after
451 theme_r.height() - toolbar_overlap, false); 446 theme_r.height() - toolbar_overlap, false);
452 447
453 // Draw center. Instead of masking out the top portion we simply skip over it 448 // Draw center. Instead of masking out the top portion we simply skip over it
454 // by incrementing by the top padding, since it's a simple rectangle. 449 // by incrementing by the top padding, since it's a simple rectangle.
455 rect.Inset(g_mask_images.l_width, tab_insets.top(), g_mask_images.r_width, 450 rect.Inset(g_mask_images.l_width, tab_insets.top(), g_mask_images.r_width,
456 toolbar_overlap); 451 toolbar_overlap);
457 canvas->TileImageInt(fill_image, rect.x(), rect.y(), g_mask_images.l_width, 452 canvas->TileImageInt(fill_image, rect.x(), rect.y(), g_mask_images.l_width,
458 tab_insets.top(), rect.width(), rect.height()); 453 tab_insets.top(), rect.width(), rect.height());
459 } 454 }
460 455
461 // Desaturates the favicon. Should only be used for when a tab encounters a
462 // network error state.
463 void PaintDesaturatedFavIcon(gfx::Canvas* canvas,
464 gfx::ImageSkia& favicon,
465 const gfx::Rect& bounds) {
466 color_utils::HSL shift = {kDesaturateHue,
467 kDesaturateSaturation,
468 kDesaturateLightness};
469 gfx::ImageSkia desaturated_favicon =
470 gfx::ImageSkiaOperations::CreateHSLShiftedImage(favicon, shift);
471 if (!bounds.IsEmpty()) {
472 canvas->DrawImageInt(desaturated_favicon, 0, 0,
473 bounds.width(), bounds.height(),
474 bounds.x(), bounds.y(), bounds.width(),
475 bounds.height(), false);
476 } else {
477 canvas->DrawImageInt(desaturated_favicon, 0, 0);
478 }
479 }
480
481 } // namespace 456 } // namespace
482 457
483 //////////////////////////////////////////////////////////////////////////////// 458 ////////////////////////////////////////////////////////////////////////////////
484 // FaviconCrashAnimation 459 // FaviconCrashAnimation
485 // 460 //
486 // A custom animation subclass to manage the favicon crash animation. 461 // A custom animation subclass to manage the favicon crash animation.
487 class Tab::FaviconCrashAnimation : public gfx::LinearAnimation, 462 class Tab::FaviconCrashAnimation : public gfx::LinearAnimation,
488 public gfx::AnimationDelegate { 463 public gfx::AnimationDelegate {
489 public: 464 public:
490 explicit FaviconCrashAnimation(Tab* target) 465 explicit FaviconCrashAnimation(Tab* target)
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
652 loading_start_time_ = base::TimeTicks(); 627 loading_start_time_ = base::TimeTicks();
653 waiting_state_ = gfx::ThrobberWaitingState(); 628 waiting_state_ = gfx::ThrobberWaitingState();
654 } 629 }
655 630
656 bool Tab::ThrobberView::CanProcessEventsWithinSubtree() const { 631 bool Tab::ThrobberView::CanProcessEventsWithinSubtree() const {
657 return false; 632 return false;
658 } 633 }
659 634
660 void Tab::ThrobberView::OnPaint(gfx::Canvas* canvas) { 635 void Tab::ThrobberView::OnPaint(gfx::Canvas* canvas) {
661 const TabRendererData::NetworkState state = owner_->data().network_state; 636 const TabRendererData::NetworkState state = owner_->data().network_state;
662 if (state == TabRendererData::NETWORK_STATE_NONE || 637 if (state == TabRendererData::NETWORK_STATE_NONE)
663 state == TabRendererData::NETWORK_STATE_ERROR)
664 return; 638 return;
665 639
666 const ui::ThemeProvider* tp = GetThemeProvider(); 640 const ui::ThemeProvider* tp = GetThemeProvider();
667 const gfx::Rect bounds = GetLocalBounds(); 641 const gfx::Rect bounds = GetLocalBounds();
668 if (state == TabRendererData::NETWORK_STATE_WAITING) { 642 if (state == TabRendererData::NETWORK_STATE_WAITING) {
669 if (waiting_start_time_ == base::TimeTicks()) 643 if (waiting_start_time_ == base::TimeTicks())
670 waiting_start_time_ = base::TimeTicks::Now(); 644 waiting_start_time_ = base::TimeTicks::Now();
671 645
672 waiting_state_.elapsed_time = base::TimeTicks::Now() - waiting_start_time_; 646 waiting_state_.elapsed_time = base::TimeTicks::Now() - waiting_start_time_;
673 gfx::PaintThrobberWaiting( 647 gfx::PaintThrobberWaiting(
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
791 void Tab::AlertStateChanged() { 765 void Tab::AlertStateChanged() {
792 Layout(); 766 Layout();
793 } 767 }
794 768
795 bool Tab::IsSelected() const { 769 bool Tab::IsSelected() const {
796 return controller_->IsTabSelected(this); 770 return controller_->IsTabSelected(this);
797 } 771 }
798 772
799 void Tab::SetData(const TabRendererData& data) { 773 void Tab::SetData(const TabRendererData& data) {
800 DCHECK(GetWidget()); 774 DCHECK(GetWidget());
775
801 if (data_.Equals(data)) 776 if (data_.Equals(data))
802 return; 777 return;
803 778
804 TabRendererData old(data_); 779 TabRendererData old(data_);
805 UpdateLoadingAnimation(data.network_state); 780 UpdateLoadingAnimation(data.network_state);
806 data_ = data; 781 data_ = data;
807 782
808 base::string16 title = data_.title; 783 base::string16 title = data_.title;
809 if (title.empty()) { 784 if (title.empty()) {
810 title = data_.loading ? 785 title = data_.loading ?
(...skipping 21 matching lines...) Expand all
832 showing_pinned_tab_title_changed_indicator_ = false; 807 showing_pinned_tab_title_changed_indicator_ = false;
833 808
834 DataChanged(old); 809 DataChanged(old);
835 810
836 Layout(); 811 Layout();
837 SchedulePaint(); 812 SchedulePaint();
838 } 813 }
839 814
840 void Tab::UpdateLoadingAnimation(TabRendererData::NetworkState state) { 815 void Tab::UpdateLoadingAnimation(TabRendererData::NetworkState state) {
841 if (state == data_.network_state && 816 if (state == data_.network_state &&
842 (state == TabRendererData::NETWORK_STATE_NONE || 817 state == TabRendererData::NETWORK_STATE_NONE) {
843 state == TabRendererData::NETWORK_STATE_ERROR)) { 818 // If the network state is none and hasn't changed, do nothing. Otherwise we
844 // If the network state is none or is an network error and hasn't changed, 819 // need to advance the animation frame.
845 // do nothing. Otherwise we need to advance the animation frame.
846 return; 820 return;
847 } 821 }
848 822
849 data_.network_state = state; 823 data_.network_state = state;
850 AdvanceLoadingAnimation(); 824 AdvanceLoadingAnimation();
851 } 825 }
852 826
853 void Tab::StartPulse() { 827 void Tab::StartPulse() {
854 pulse_animation_->StartThrobbing(std::numeric_limits<int>::max()); 828 pulse_animation_->StartThrobbing(std::numeric_limits<int>::max());
855 } 829 }
(...skipping 710 matching lines...) Expand 10 before | Expand all | Expand 10 after
1566 const gfx::Rect& favicon_draw_bounds) { 1540 const gfx::Rect& favicon_draw_bounds) {
1567 // The pinned tab title changed indicator consists of two parts: 1541 // The pinned tab title changed indicator consists of two parts:
1568 // . a clear (totally transparent) part over the bottom right (or left in rtl) 1542 // . a clear (totally transparent) part over the bottom right (or left in rtl)
1569 // of the favicon. This is done by drawing the favicon to a canvas, then 1543 // of the favicon. This is done by drawing the favicon to a canvas, then
1570 // drawing the clear part on top of the favicon. 1544 // drawing the clear part on top of the favicon.
1571 // . a circle in the bottom right (or left in rtl) of the favicon. 1545 // . a circle in the bottom right (or left in rtl) of the favicon.
1572 if (!favicon_.isNull()) { 1546 if (!favicon_.isNull()) {
1573 const float kIndicatorCropRadius = 4.5; 1547 const float kIndicatorCropRadius = 4.5;
1574 gfx::Canvas icon_canvas(gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize), 1548 gfx::Canvas icon_canvas(gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize),
1575 canvas->image_scale(), false); 1549 canvas->image_scale(), false);
1576 1550 icon_canvas.DrawImageInt(favicon_, 0, 0);
1577 if (data().network_state == TabRendererData::NETWORK_STATE_ERROR)
1578 PaintDesaturatedFavIcon(&icon_canvas, favicon_, gfx::Rect());
1579 else
1580 icon_canvas.DrawImageInt(favicon_, 0, 0);
1581
1582 SkPaint clear_paint; 1551 SkPaint clear_paint;
1583 clear_paint.setAntiAlias(true); 1552 clear_paint.setAntiAlias(true);
1584 clear_paint.setXfermodeMode(SkXfermode::kClear_Mode); 1553 clear_paint.setXfermodeMode(SkXfermode::kClear_Mode);
1585 const int circle_x = base::i18n::IsRTL() ? 0 : gfx::kFaviconSize; 1554 const int circle_x = base::i18n::IsRTL() ? 0 : gfx::kFaviconSize;
1586 icon_canvas.DrawCircle(gfx::PointF(circle_x, gfx::kFaviconSize), 1555 icon_canvas.DrawCircle(gfx::PointF(circle_x, gfx::kFaviconSize),
1587 kIndicatorCropRadius, clear_paint); 1556 kIndicatorCropRadius, clear_paint);
1588 canvas->DrawImageInt(gfx::ImageSkia(icon_canvas.ExtractImageRep()), 0, 0, 1557 canvas->DrawImageInt(gfx::ImageSkia(icon_canvas.ExtractImageRep()), 0, 0,
1589 favicon_draw_bounds.width(), 1558 favicon_draw_bounds.width(),
1590 favicon_draw_bounds.height(), favicon_draw_bounds.x(), 1559 favicon_draw_bounds.height(), favicon_draw_bounds.x(),
1591 favicon_draw_bounds.y(), favicon_draw_bounds.width(), 1560 favicon_draw_bounds.y(), favicon_draw_bounds.width(),
(...skipping 16 matching lines...) Expand all
1608 1577
1609 void Tab::PaintIcon(gfx::Canvas* canvas) { 1578 void Tab::PaintIcon(gfx::Canvas* canvas) {
1610 gfx::Rect bounds = favicon_bounds_; 1579 gfx::Rect bounds = favicon_bounds_;
1611 bounds.set_x(GetMirroredXForRect(bounds)); 1580 bounds.set_x(GetMirroredXForRect(bounds));
1612 bounds.Offset(0, favicon_hiding_offset_); 1581 bounds.Offset(0, favicon_hiding_offset_);
1613 bounds.Intersect(GetContentsBounds()); 1582 bounds.Intersect(GetContentsBounds());
1614 if (bounds.IsEmpty()) 1583 if (bounds.IsEmpty())
1615 return; 1584 return;
1616 1585
1617 // Throbber will do its own painting. 1586 // Throbber will do its own painting.
1618 if (data().network_state != TabRendererData::NETWORK_STATE_NONE && 1587 if (data().network_state != TabRendererData::NETWORK_STATE_NONE)
1619 data().network_state != TabRendererData::NETWORK_STATE_ERROR)
1620 return; 1588 return;
1621 1589
1622 // Ensure that |favicon_| is created. 1590 // Ensure that |favicon_| is created.
1623 if (favicon_.isNull()) { 1591 if (favicon_.isNull()) {
1624 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance(); 1592 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
1625 favicon_ = should_display_crashed_favicon_ 1593 favicon_ = should_display_crashed_favicon_
1626 ? *rb->GetImageSkiaNamed(IDR_CRASH_SAD_FAVICON) 1594 ? *rb->GetImageSkiaNamed(IDR_CRASH_SAD_FAVICON)
1627 : data().favicon; 1595 : data().favicon;
1628 // Themify the icon if it's a chrome:// page or if it's the sadtab favicon. 1596 // Themify the icon if it's a chrome:// page or if it's the sadtab favicon.
1629 // This ensures chrome:// pages are visible over the tab background. This is 1597 // This ensures chrome:// pages are visible over the tab background. This is
1630 // similar to code in the bookmarks bar. 1598 // similar to code in the bookmarks bar.
1631 if (!favicon_.isNull() && 1599 if (!favicon_.isNull() &&
1632 (should_display_crashed_favicon_ || 1600 (should_display_crashed_favicon_ ||
1633 favicon_.BackedBySameObjectAs( 1601 favicon_.BackedBySameObjectAs(
1634 *rb->GetImageSkiaNamed(IDR_DEFAULT_FAVICON)) || 1602 *rb->GetImageSkiaNamed(IDR_DEFAULT_FAVICON)) ||
1635 ShouldThemifyFaviconForUrl(data().url))) { 1603 ShouldThemifyFaviconForUrl(data().url))) {
1636 favicon_ = gfx::ImageSkiaOperations::CreateHSLShiftedImage( 1604 favicon_ = gfx::ImageSkiaOperations::CreateHSLShiftedImage(
1637 favicon_, GetThemeProvider()->GetTint(ThemeProperties::TINT_BUTTONS)); 1605 favicon_, GetThemeProvider()->GetTint(ThemeProperties::TINT_BUTTONS));
1638 } 1606 }
1639 } 1607 }
1640 1608
1641 if (showing_pinned_tab_title_changed_indicator_ && 1609 if (showing_pinned_tab_title_changed_indicator_ &&
1642 !should_display_crashed_favicon_) { 1610 !should_display_crashed_favicon_) {
1643 PaintPinnedTabTitleChangedIndicatorAndIcon(canvas, bounds); 1611 PaintPinnedTabTitleChangedIndicatorAndIcon(canvas, bounds);
1644 } else if (!favicon_.isNull()) { 1612 } else if (!favicon_.isNull()) {
1645 // Desaturate favicons of tabs with network errors. 1613 canvas->DrawImageInt(favicon_, 0, 0, bounds.width(), bounds.height(),
1646 if (data().network_state == TabRendererData::NETWORK_STATE_ERROR) { 1614 bounds.x(), bounds.y(), bounds.width(),
1647 PaintDesaturatedFavIcon(canvas, favicon_, bounds); 1615 bounds.height(), false);
1648 } else {
1649 canvas->DrawImageInt(favicon_, 0, 0, bounds.width(), bounds.height(),
1650 bounds.x(), bounds.y(), bounds.width(),
1651 bounds.height(), false);
1652 }
1653 } 1616 }
1654 } 1617 }
1655 1618
1656 void Tab::AdvanceLoadingAnimation() { 1619 void Tab::AdvanceLoadingAnimation() {
1657 const TabRendererData::NetworkState state = data().network_state; 1620 const TabRendererData::NetworkState state = data().network_state;
1658 if (controller_->IsImmersiveStyle()) { 1621 if (controller_->IsImmersiveStyle()) {
1659 throbber_->SetVisible(false); 1622 throbber_->SetVisible(false);
1660 if (state == TabRendererData::NETWORK_STATE_WAITING) { 1623 if (state == TabRendererData::NETWORK_STATE_WAITING) {
1661 // Waiting steps backwards. 1624 // Waiting steps backwards.
1662 immersive_loading_step_ = 1625 immersive_loading_step_ =
1663 (immersive_loading_step_ - 1 + kImmersiveLoadingStepCount) % 1626 (immersive_loading_step_ - 1 + kImmersiveLoadingStepCount) %
1664 kImmersiveLoadingStepCount; 1627 kImmersiveLoadingStepCount;
1665 } else if (state == TabRendererData::NETWORK_STATE_LOADING) { 1628 } else if (state == TabRendererData::NETWORK_STATE_LOADING) {
1666 immersive_loading_step_ = 1629 immersive_loading_step_ =
1667 (immersive_loading_step_ + 1) % kImmersiveLoadingStepCount; 1630 (immersive_loading_step_ + 1) % kImmersiveLoadingStepCount;
1668 } else { 1631 } else {
1669 immersive_loading_step_ = 0; 1632 immersive_loading_step_ = 0;
1670 } 1633 }
1671 1634
1672 SchedulePaintInRect(GetImmersiveBarRect()); 1635 SchedulePaintInRect(GetImmersiveBarRect());
1673 return; 1636 return;
1674 } 1637 }
1675 1638
1676 if (state == TabRendererData::NETWORK_STATE_NONE || 1639 if (state == TabRendererData::NETWORK_STATE_NONE) {
1677 state == TabRendererData::NETWORK_STATE_ERROR) {
1678 throbber_->ResetStartTimes(); 1640 throbber_->ResetStartTimes();
1679 throbber_->SetVisible(false); 1641 throbber_->SetVisible(false);
1680 ScheduleIconPaint(); 1642 ScheduleIconPaint();
1681 return; 1643 return;
1682 } 1644 }
1683 1645
1684 // Since the throbber can animate for a long time, paint to a separate layer 1646 // Since the throbber can animate for a long time, paint to a separate layer
1685 // when possible to reduce repaint overhead. 1647 // when possible to reduce repaint overhead.
1686 const bool paint_to_layer = controller_->CanPaintThrobberToLayer(); 1648 const bool paint_to_layer = controller_->CanPaintThrobberToLayer();
1687 if (paint_to_layer != !!throbber_->layer()) { 1649 if (paint_to_layer != !!throbber_->layer()) {
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
1812 gfx::Rect Tab::GetImmersiveBarRect() const { 1774 gfx::Rect Tab::GetImmersiveBarRect() const {
1813 // The main bar is as wide as the normal tab's horizontal top line. 1775 // The main bar is as wide as the normal tab's horizontal top line.
1814 // This top line of the tab extends a few pixels left and right of the 1776 // This top line of the tab extends a few pixels left and right of the
1815 // center image due to pixels in the rounded corner images. 1777 // center image due to pixels in the rounded corner images.
1816 const int kBarPadding = 1; 1778 const int kBarPadding = 1;
1817 int main_bar_left = g_active_images.l_width - kBarPadding; 1779 int main_bar_left = g_active_images.l_width - kBarPadding;
1818 int main_bar_right = width() - g_active_images.r_width + kBarPadding; 1780 int main_bar_right = width() - g_active_images.r_width + kBarPadding;
1819 return gfx::Rect( 1781 return gfx::Rect(
1820 main_bar_left, 0, main_bar_right - main_bar_left, kImmersiveBarHeight); 1782 main_bar_left, 0, main_bar_right - main_bar_left, kImmersiveBarHeight);
1821 } 1783 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc ('k') | chrome/browser/ui/views/tabs/tab_renderer_data.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698