Index: chrome/browser/ui/views/tabs/tab.cc |
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc |
index 6d0d78ae342129de7cfe6e2eb8a11b18c20d701b..c828f1f42e515968c7d11840eec806832e05f77a 100644 |
--- a/chrome/browser/ui/views/tabs/tab.cc |
+++ b/chrome/browser/ui/views/tabs/tab.cc |
@@ -137,6 +137,65 @@ const int kImmersiveLoadingStepCount = 32; |
const char kTabCloseButtonName[] = "TabCloseButton"; |
const int kTabCloseButtonSize = 16; |
+// Layer-backed view for updating a waiting or loading tab spinner. |
Peter Kasting
2015/10/09 08:03:23
Tiny nit: Please be consistent about using the wor
tapted
2015/10/09 11:00:31
Done.
|
+class ThrobberView : public views::View { |
+ public: |
+ explicit ThrobberView(Tab* owner) : owner_(owner) { |
Peter Kasting
2015/10/09 08:03:24
Don't define any of these class methods inline; de
tapted
2015/10/09 11:00:31
Done.
|
+ // Since the throbber animates, paint to a separate layer do reduce repaint |
Peter Kasting
2015/10/09 08:03:24
Nit: do -> to ?
Maybe you want "can animate for a
tapted
2015/10/09 11:00:31
Done.
|
+ // overheads. |
Peter Kasting
2015/10/09 08:03:23
Nit: overheads -> overhead
tapted
2015/10/09 11:00:31
Done.
|
+ SetPaintToLayer(true); |
+ SetFillsBoundsOpaquely(false); |
+ } |
+ |
+ // views::View: |
+ bool CanProcessEventsWithinSubtree() const override { return false; } |
+ |
+ void OnPaint(gfx::Canvas* canvas) override { |
+ const TabRendererData::NetworkState state = owner_->data().network_state; |
+ if (state == TabRendererData::NETWORK_STATE_NONE) |
+ return; |
+ |
+ const gfx::Rect bounds = GetLocalBounds(); |
Peter Kasting
2015/10/09 08:03:23
Nit: Might as well define this just below |tp|, th
tapted
2015/10/09 11:00:31
Done.
|
+ |
+ // Paint network activity (aka throbber) animation frame. |
Peter Kasting
2015/10/09 08:03:24
Nit: It's weird to say "aka throbber" in a class w
tapted
2015/10/09 11:00:31
Done.
|
+ ui::ThemeProvider* tp = GetThemeProvider(); |
+ if (state == TabRendererData::NETWORK_STATE_WAITING) { |
+ if (waiting_start_time_ == base::TimeTicks()) |
+ waiting_start_time_ = base::TimeTicks::Now(); |
+ |
+ waiting_state_.elapsed_time = |
+ base::TimeTicks::Now() - waiting_start_time_; |
+ gfx::PaintThrobberWaiting( |
+ canvas, bounds, tp->GetColor(ThemeProperties::COLOR_THROBBER_WAITING), |
+ waiting_state_.elapsed_time); |
+ } else { |
+ if (loading_start_time_ == base::TimeTicks()) |
+ loading_start_time_ = base::TimeTicks::Now(); |
+ |
+ waiting_state_.color = |
+ tp->GetColor(ThemeProperties::COLOR_THROBBER_WAITING); |
+ gfx::PaintThrobberSpinningAfterWaiting( |
+ canvas, bounds, |
+ tp->GetColor(ThemeProperties::COLOR_THROBBER_SPINNING), |
+ base::TimeTicks::Now() - loading_start_time_, &waiting_state_); |
+ } |
+ } |
+ |
+ private: |
+ Tab* owner_; // Weak. Owns |this|. |
+ |
+ // The point in time when the tab icon was first painted in the waiting state. |
+ base::TimeTicks waiting_start_time_; |
+ |
+ // The point in time when the tab icon was first painted in the loading state. |
+ base::TimeTicks loading_start_time_; |
+ |
+ // Paint state for the throbber after the most recent waiting paint. |
+ gfx::ThrobberWaitingState waiting_state_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ThrobberView); |
+}; |
+ |
void DrawIconAtLocation(gfx::Canvas* canvas, |
const gfx::ImageSkia& image, |
int image_offset, |
@@ -412,6 +471,7 @@ Tab::Tab(TabController* controller) |
favicon_hiding_offset_(0), |
immersive_loading_step_(0), |
should_display_crashed_favicon_(false), |
+ throbber_(nullptr), |
media_indicator_button_(nullptr), |
close_button_(nullptr), |
title_(new views::Label()), |
@@ -440,6 +500,9 @@ Tab::Tab(TabController* controller) |
SetEventTargeter( |
scoped_ptr<views::ViewTargeter>(new views::ViewTargeter(this))); |
+ throbber_ = new ThrobberView(this); |
+ AddChildView(throbber_); |
+ |
media_indicator_button_ = new MediaIndicatorButton(this); |
AddChildView(media_indicator_button_); |
@@ -494,6 +557,7 @@ void Tab::SetData(const TabRendererData& data) { |
return; |
TabRendererData old(data_); |
+ UpdateLoadingAnimation(data.network_state); |
tapted
2015/10/09 06:39:02
I noticed the throbber would hang around with some
|
data_ = data; |
base::string16 title = data_.title; |
@@ -552,9 +616,8 @@ void Tab::UpdateLoadingAnimation(TabRendererData::NetworkState state) { |
return; |
} |
- TabRendererData::NetworkState old_state = data_.network_state; |
data_.network_state = state; |
- AdvanceLoadingAnimation(old_state, state); |
+ AdvanceLoadingAnimation(state); |
} |
void Tab::StartPulse() { |
@@ -787,6 +850,7 @@ void Tab::Layout() { |
favicon_bounds_.set_y(lb.y() + (lb.height() - gfx::kFaviconSize + 1) / 2); |
MaybeAdjustLeftForPinnedTab(&favicon_bounds_); |
} |
+ throbber_->SetBoundsRect(favicon_bounds_); |
showing_close_button_ = ShouldShowCloseBox(); |
if (showing_close_button_) { |
@@ -1347,28 +1411,7 @@ void Tab::PaintIcon(gfx::Canvas* canvas) { |
bounds.set_x(GetMirroredXForRect(bounds)); |
if (data().network_state != TabRendererData::NETWORK_STATE_NONE) { |
- // Paint network activity (aka throbber) animation frame. |
- ui::ThemeProvider* tp = GetThemeProvider(); |
- if (data().network_state == TabRendererData::NETWORK_STATE_WAITING) { |
- if (waiting_start_time_ == base::TimeTicks()) |
- waiting_start_time_ = base::TimeTicks::Now(); |
- |
- waiting_state_.elapsed_time = |
- base::TimeTicks::Now() - waiting_start_time_; |
- gfx::PaintThrobberWaiting( |
- canvas, bounds, tp->GetColor(ThemeProperties::COLOR_THROBBER_WAITING), |
- waiting_state_.elapsed_time); |
- } else { |
- if (loading_start_time_ == base::TimeTicks()) |
- loading_start_time_ = base::TimeTicks::Now(); |
- |
- waiting_state_.color = |
- tp->GetColor(ThemeProperties::COLOR_THROBBER_WAITING); |
- gfx::PaintThrobberSpinningAfterWaiting( |
- canvas, bounds, |
- tp->GetColor(ThemeProperties::COLOR_THROBBER_SPINNING), |
- base::TimeTicks::Now() - loading_start_time_, &waiting_state_); |
- } |
+ // Throbber will do its own painting. |
} else if (should_display_crashed_favicon_) { |
// Paint crash favicon. |
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
@@ -1387,27 +1430,37 @@ void Tab::PaintIcon(gfx::Canvas* canvas) { |
} |
} |
-void Tab::AdvanceLoadingAnimation(TabRendererData::NetworkState old_state, |
- TabRendererData::NetworkState state) { |
- if (state == TabRendererData::NETWORK_STATE_WAITING) { |
- // Waiting steps backwards. |
- immersive_loading_step_ = |
- (immersive_loading_step_ - 1 + kImmersiveLoadingStepCount) % |
- kImmersiveLoadingStepCount; |
- } else if (state == TabRendererData::NETWORK_STATE_LOADING) { |
- immersive_loading_step_ = (immersive_loading_step_ + 1) % |
- kImmersiveLoadingStepCount; |
- } else { |
- waiting_start_time_ = base::TimeTicks(); |
- loading_start_time_ = base::TimeTicks(); |
- waiting_state_ = gfx::ThrobberWaitingState(); |
- immersive_loading_step_ = 0; |
- } |
+void Tab::AdvanceLoadingAnimation(TabRendererData::NetworkState state) { |
if (controller_->IsImmersiveStyle()) { |
+ if (state == TabRendererData::NETWORK_STATE_WAITING) { |
+ // Waiting steps backwards. |
+ immersive_loading_step_ = |
+ (immersive_loading_step_ - 1 + kImmersiveLoadingStepCount) % |
+ kImmersiveLoadingStepCount; |
+ } else if (state == TabRendererData::NETWORK_STATE_LOADING) { |
+ immersive_loading_step_ = |
+ (immersive_loading_step_ + 1) % kImmersiveLoadingStepCount; |
+ } else { |
+ immersive_loading_step_ = 0; |
+ } |
+ |
SchedulePaintInRect(GetImmersiveBarRect()); |
- } else { |
- ScheduleIconPaint(); |
+ return; |
+ } |
+ |
+ // To ensure the throbber layer does not paint over stacked or dragged tabs, |
+ // hide it when the favicon would be clipped out. Check for any clipping on |
+ // the left since the shoulder of a dragged tab can still paint over the icon. |
+ gfx::Rect clip = GetLocalBounds(); |
+ const bool needs_throbber = state != TabRendererData::NETWORK_STATE_NONE && |
+ controller_->ShouldPaintTab(this, &clip) && |
+ clip.x() == 0 && clip.Contains(favicon_bounds_); |
+ |
+ if (needs_throbber != throbber_->visible()) { |
+ ScheduleIconPaint(); // Repaint the icon area to update favicon visibility. |
+ throbber_->SetVisible(needs_throbber); |
Peter Kasting
2015/10/09 08:03:23
Nit: For clarity, you might want to reverse these
tapted
2015/10/09 11:00:31
Done.
|
} |
+ throbber_->SchedulePaint(); |
} |
int Tab::IconCapacity() const { |