Chromium Code Reviews| 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 { |