Commit 98d67224 authored by Peter Boström's avatar Peter Boström Committed by Commit Bot

Interpolate loading progress in tab animation

Instead of skipping to the new load-progress value as it arrives,
interpolate to it. This results in a smoother animation as the
load-progress callbacks can be fairly sparse (and jump from 20% to 80%
for instance).

Drives animations off of the same timer that is used for the throbbing
state. This will hopefully address a performance regression as the
throbbing timer, progress fade-out animation and favicon fade-in
animation were all scheduling separate high-frequency repainting of the
tab icon.

Bug: chromium:903827, chromium:903147, chromium:902475, chromium:901751

progress

Change-Id: Iad2a24d94206d5871a5cacc5e56d072161407940
Reviewed-on: https://chromium-review.googlesource.com/c/1330345
Commit-Queue: Peter Boström <pbos@chromium.org>
Reviewed-by: default avatarElly Fong-Jones <ellyjones@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607316}
parent 8a288cba
......@@ -814,7 +814,7 @@ void BrowserView::UpdateDevTools() {
}
void BrowserView::UpdateLoadingAnimations(bool should_animate) {
if (should_animate) {
if (should_animate || tabstrip_->IsAnyIconAnimating()) {
if (!loading_animation_timer_.IsRunning()) {
// Loads are happening, and the timer isn't running, so start it.
loading_animation_start_ = base::TimeTicks::Now();
......
......@@ -742,6 +742,10 @@ void Tab::StepLoadingAnimation(const base::TimeDelta& elapsed_time) {
icon_->SetCanPaintToLayer(controller_->CanPaintThrobberToLayer());
}
bool Tab::ShowingLoadingAnimation() const {
return icon_->ShowingLoadingAnimation();
}
void Tab::StartPulse() {
pulse_animation_.StartThrobbing(std::numeric_limits<int>::max());
}
......
......@@ -151,6 +151,8 @@ class Tab : public gfx::AnimationDelegate,
// throbbers in sync.
void StepLoadingAnimation(const base::TimeDelta& elapsed_time);
bool ShowingLoadingAnimation() const;
// Starts/Stops a pulse animation.
void StartPulse();
void StopPulse();
......
......@@ -26,6 +26,13 @@
namespace {
// Note: The excess (part above 1.0) is used as a fade-out effect, so if this
// value is 1.5, then 50% of the progress indicator animation will be used for
// fade-out time after the loading sequence is complete.
// Also note that the progress indicator animation is capped to the actual load
// progress.
constexpr double kProgressIndicatorAnimationDuration = 1.5;
bool UseNewLoadingAnimation() {
return base::FeatureList::IsEnabled(features::kNewTabLoadingAnimation);
}
......@@ -81,10 +88,9 @@ class TabIcon::CrashAnimation : public gfx::LinearAnimation,
};
TabIcon::TabIcon()
: progress_indicator_fade_out_animation_(
base::TimeDelta::FromMilliseconds(200),
gfx::LinearAnimation::kDefaultFrameRate,
this),
: loading_progress_timer_(base::TimeDelta::FromMilliseconds(600),
gfx::LinearAnimation::kDefaultFrameRate,
this),
favicon_fade_in_animation_(base::TimeDelta::FromMilliseconds(200),
gfx::LinearAnimation::kDefaultFrameRate,
this) {
......@@ -136,7 +142,7 @@ bool TabIcon::ShowingLoadingAnimation() const {
if (inhibit_loading_animation_)
return false;
if (progress_indicator_fade_out_animation_.is_animating() ||
if (loading_progress_timer_.is_animating() ||
favicon_fade_in_animation_.is_animating()) {
return true;
}
......@@ -200,14 +206,12 @@ void TabIcon::OnThemeChanged() {
themed_favicon_ = ThemeImage(favicon_);
}
void TabIcon::AnimationProgressed(const gfx::Animation* animation) {
SchedulePaint();
}
void TabIcon::AnimationEnded(const gfx::Animation* animation) {
// After the last animation ends it's possible we should not paint to a layer
// anymore.
RefreshLayer();
// Make sure that the final frame of the animation gets painted.
SchedulePaint();
}
void TabIcon::PaintAttentionIndicatorAndIcon(gfx::Canvas* canvas,
......@@ -246,16 +250,30 @@ void TabIcon::PaintAttentionIndicatorAndIcon(gfx::Canvas* canvas,
void TabIcon::PaintLoadingProgressIndicator(gfx::Canvas* canvas,
gfx::RectF bounds,
SkColor color) {
bounds.set_width(std::max(
bounds.height(), static_cast<float>(loading_progress_ * bounds.width())));
double animation_value = loading_progress_timer_.GetCurrentValue() *
kProgressIndicatorAnimationDuration;
if (network_state_ == TabNetworkState::kLoading) {
// While we're loading, clamp to the loading process (which cannot go above
// 1.0) to make sure that we don't start the fade-out during kLoading, even
// if loading progress has previously been reported as 1.0.
animation_value = std::min(loading_progress_, animation_value);
}
const double loading_progress = std::min(animation_value, 1.0);
bounds.set_width(bounds.height() +
loading_progress * (bounds.width() - bounds.height()));
cc::PaintFlags flags;
flags.setColor(color);
flags.setStyle(cc::PaintFlags::kFill_Style);
flags.setAntiAlias(true);
flags.setAlpha(
SK_AlphaOPAQUE *
(1.0 - progress_indicator_fade_out_animation_.GetCurrentValue()));
if (animation_value > 1.0) {
// The part of kProgressIndicatorAnimationDuration above 1.0 is translated
// into an alpha value used as a linear fade-out effect.
flags.setAlpha(SK_AlphaOPAQUE *
(1.0 - (animation_value - 1.0) /
(kProgressIndicatorAnimationDuration - 1.0)));
}
canvas->DrawRoundRect(bounds, bounds.height() / 2, flags);
}
......@@ -373,12 +391,14 @@ void TabIcon::SetNetworkState(TabNetworkState network_state,
TabNetworkState old_state = network_state_;
network_state_ = network_state;
if (network_state_ == TabNetworkState::kLoading)
if (network_state_ == TabNetworkState::kLoading) {
// When transitioning to loading, reset the progress indicatator + timer.
loading_progress_ = 0.0;
loading_progress_timer_.SetCurrentValue(0);
}
if (old_state == TabNetworkState::kLoading) {
loading_progress_ = 1.0;
progress_indicator_fade_out_animation_.Start();
// This fades in the placeholder favicon if no favicon has loaded so far.
if (!favicon_fade_in_animation_.is_animating() &&
favicon_fade_in_animation_.GetCurrentValue() == 0.0) {
......@@ -390,8 +410,8 @@ void TabIcon::SetNetworkState(TabNetworkState network_state,
// Reset favicon and tab-loading animations
favicon_fade_in_animation_.Stop();
favicon_fade_in_animation_.SetCurrentValue(0.0);
progress_indicator_fade_out_animation_.Stop();
progress_indicator_fade_out_animation_.SetCurrentValue(0.0);
loading_progress_timer_.Stop();
loading_progress_timer_.SetCurrentValue(0.0);
}
SchedulePaint();
}
......@@ -400,8 +420,14 @@ void TabIcon::SetNetworkState(TabNetworkState network_state,
// sure it only increases.
if (network_state_ == TabNetworkState::kLoading &&
loading_progress_ < load_progress) {
// Clamp the loading progress timer to the currently visible value. Note
// that the animation plays a fade-out effect after loading_progress_ is
// full, so filling the bar only uses a fraction of the timer.
loading_progress_timer_.SetCurrentValue(
std::min(loading_progress_timer_.GetCurrentValue(),
loading_progress_ / kProgressIndicatorAnimationDuration));
loading_progress_ = load_progress;
SchedulePaint();
loading_progress_timer_.Start();
}
}
......
......@@ -72,7 +72,6 @@ class TabIcon : public views::View, public gfx::AnimationDelegate {
void OnThemeChanged() override;
// gfx::AnimationDelegate:
void AnimationProgressed(const gfx::Animation* animation) override;
void AnimationEnded(const gfx::Animation* animation) override;
// Paints the attention indicator and |favicon_| at the given location.
......@@ -152,17 +151,14 @@ class TabIcon : public views::View, public gfx::AnimationDelegate {
// it will be drawn off the bottom.
double hiding_fraction_ = 0.0;
// Fade-out animation after a tab has loaded to not instantly remove the
// progress bar at 100%.
gfx::LinearAnimation progress_indicator_fade_out_animation_;
// Loading progress used for drawing the progress indicator.
double loading_progress_ = 1.0;
gfx::LinearAnimation loading_progress_timer_;
// Fade-in animation for the favicon. Starts when a favicon loads or the tab
// is no longer loading. The latter case will fade into a placeholder icon.
gfx::LinearAnimation favicon_fade_in_animation_;
// Loading progress used for drawing the progress indicator.
double loading_progress_ = 1.0;
// Crash animation (in place of favicon). Lazily created since most of the
// time it will be unneeded.
std::unique_ptr<CrashAnimation> crash_animation_;
......
......@@ -390,6 +390,14 @@ void TabStrip::UpdateLoadingAnimations(const base::TimeDelta& elapsed_time) {
tab_at(i)->StepLoadingAnimation(elapsed_time);
}
bool TabStrip::IsAnyIconAnimating() const {
for (int i = 0; i < tab_count(); i++) {
if (tab_at(i)->ShowingLoadingAnimation())
return true;
}
return false;
}
void TabStrip::SetStackedLayout(bool stacked_layout) {
if (stacked_layout == stacked_layout_)
return;
......
......@@ -114,6 +114,8 @@ class TabStrip : public views::AccessiblePaneView,
// keep the throbbers in sync.
void UpdateLoadingAnimations(const base::TimeDelta& elapsed_time);
bool IsAnyIconAnimating() const;
// If |adjust_layout| is true the stacked layout changes based on whether the
// user uses a mouse or a touch device with the tabstrip.
void set_adjust_layout(bool adjust_layout) { adjust_layout_ = adjust_layout; }
......
......@@ -300,8 +300,8 @@ class TabTest : public ChromeViewsTestBase {
}
static void FinishRunningLoadingAnimations(TabIcon* icon) {
for (auto* animation : {&icon->progress_indicator_fade_out_animation_,
&icon->favicon_fade_in_animation_}) {
for (auto* animation :
{&icon->loading_progress_timer_, &icon->favicon_fade_in_animation_}) {
if (!animation->is_animating())
continue;
animation->Stop();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment