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

Unified Diff: chrome/browser/ui/views/tabs/tab.cc

Issue 1400783002: Use a layer transform for the waiting throbber Base URL: https://chromium.googlesource.com/chromium/src.git@20151006-MacViewsBrowser-Power
Patch Set: Fix color Created 5 years, 2 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/ui/views/tabs/tab.h ('k') | ui/gfx/paint_throbber.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 c828f1f42e515968c7d11840eec806832e05f77a..b6056cde652713cdf221936659d24353faf4c875 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -30,6 +30,8 @@
#include "ui/base/models/list_selection_model.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/theme_provider.h"
+#include "ui/compositor/layer_animator.h"
+#include "ui/compositor/paint_recorder.h"
#include "ui/gfx/animation/animation_container.h"
#include "ui/gfx/animation/multi_animation.h"
#include "ui/gfx/animation/throb_animation.h"
@@ -137,65 +139,6 @@ const int kImmersiveLoadingStepCount = 32;
const char kTabCloseButtonName[] = "TabCloseButton";
const int kTabCloseButtonSize = 16;
-// Layer-backed view for updating a waiting or loading tab spinner.
-class ThrobberView : public views::View {
- public:
- explicit ThrobberView(Tab* owner) : owner_(owner) {
- // Since the throbber animates, paint to a separate layer do reduce repaint
- // overheads.
- 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();
-
- // Paint network activity (aka throbber) animation frame.
- 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,
@@ -451,6 +394,170 @@ Tab::ImageCacheEntry::ImageCacheEntry()
Tab::ImageCacheEntry::~ImageCacheEntry() {}
////////////////////////////////////////////////////////////////////////////////
+// ThrobberView
+
+// Layer-backed view for updating a waiting or loading tab spinner.
+class Tab::ThrobberView : public views::View {
+ public:
+ explicit ThrobberView(Tab* owner) : owner_(owner), waiting_arc_(180) {
+ // Since the throbber animates, paint to a separate layer do reduce repaint
+ // overheads.
+ SetPaintToLayer(true);
+ SetFillsBoundsOpaquely(false);
+
+ waiting_mask_.SetFillsBoundsOpaquely(false);
+ waiting_mask_.SetMasksToBounds(true);
+ waiting_mask_.Add(waiting_arc_.layer());
+ }
+
+ void SchedulePaintIfRequired() {
+ if (NeedsPaint())
+ SchedulePaint();
+ }
+
+ // views::View:
+ bool CanProcessEventsWithinSubtree() const override { return false; }
+
+ void OnBoundsChanged(const gfx::Rect& previous_bounds) override {
+ gfx::Rect bounds = GetLocalBounds();
+ waiting_arc_.layer()->SetBounds(
+ gfx::Rect(0, 0, bounds.width() * Arc::kAA, bounds.height() * Arc::kAA));
+
+ bounds.set_width(bounds.width() / 2);
+ waiting_mask_.SetBounds(bounds);
+ }
+
+ void OnPaint(gfx::Canvas* canvas) override {
+ if (state_ == TabRendererData::NETWORK_STATE_NONE)
+ return;
+
+ const gfx::Rect bounds = GetLocalBounds();
+
+ // Paint network activity (aka throbber) animation frame.
+ ui::ThemeProvider* tp = owner_->GetThemeProvider();
+ if (state_ == TabRendererData::NETWORK_STATE_WAITING) {
+ // Painted by Arc.
+ } 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:
+ class Arc : public ui::LayerDelegate {
+ public:
+ // Since the rotation transform mis-aligns the pixel anti-aliasing done by
+ // Skia, perform a kind of FSAA by drawing on a larger canvas and scaling
+ // down as part of the transform.
+ static const int kAA = 1;
+
+ explicit Arc(SkScalar sweep)
+ : color_(SK_ColorRED), sweep_(sweep), layer_(ui::LAYER_TEXTURED) {
+ layer_.set_delegate(this);
+ layer_.SetFillsBoundsOpaquely(false);
+ }
+
+ ui::Layer* layer() { return &layer_; }
+
+ void set_color(SkColor color) { color_ = color; }
+
+ void SetAngle(SkScalar angle) {
+ const gfx::Size size = layer()->size();
+ gfx::Transform transform;
+ transform.Translate(size.width() / 2.0 / kAA, size.height() / 2.0 / kAA);
+ transform.Rotate(-angle);
+ transform.Scale(1.0 / kAA, 1.0 / kAA);
+ transform.Translate(-size.width() / 2, -size.height() / 2);
+ layer()->SetTransform(transform);
+ }
+
+ // LayerDelegate:
+ void OnPaintLayer(const ui::PaintContext& context) override {
+ const gfx::Size size = layer()->size();
+ ui::PaintRecorder recorder(context, size);
+ gfx::PaintThrobberArc(recorder.canvas(), gfx::Rect(size), color_, -90,
+ sweep_);
+ }
+
+ void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {}
+ void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
+ base::Closure PrepareForLayerBoundsChange() override {
+ return base::Closure();
+ }
+
+ private:
+ SkColor color_;
+ SkScalar sweep_;
+ ui::Layer layer_;
+
+ DISALLOW_COPY_AND_ASSIGN(Arc);
+ };
+
+ void ApplyWaitingRotation(const base::TimeDelta& elapsed_time) {
+ const base::TimeDelta revolution_time =
+ base::TimeDelta::FromMilliseconds(1320);
+ bool needs_mask = elapsed_time < revolution_time / 2;
+ waiting_mask_.SetMasksToBounds(needs_mask);
+ waiting_arc_.SetAngle(360 * waiting_state_.elapsed_time / revolution_time);
+ waiting_arc_.set_color(
+ GetThemeProvider()->GetColor(ThemeProperties::COLOR_THROBBER_WAITING));
+ }
+
+ bool NeedsPaint() {
+ if (bounds().IsEmpty())
+ return false;
+
+ TabRendererData::NetworkState new_state = owner_->data().network_state;
+ const bool changing_state = new_state != state_;
+
+ // Waiting throbber is fully layer-backed.
+ if (new_state == TabRendererData::NETWORK_STATE_WAITING) {
+ if (waiting_start_time_ == base::TimeTicks())
+ waiting_start_time_ = base::TimeTicks::Now();
+
+ state_ = new_state;
+ waiting_state_.elapsed_time =
+ base::TimeTicks::Now() - waiting_start_time_;
+ layer()->Add(&waiting_mask_);
+ ApplyWaitingRotation(waiting_state_.elapsed_time);
+ return changing_state;
+ }
+
+ if (state_ == TabRendererData::NETWORK_STATE_WAITING)
+ layer()->Remove(&waiting_mask_);
+
+ state_ = new_state;
+
+ return true;
+ }
+
+ Tab* owner_; // Weak. Owns this.
+
+ TabRendererData::NetworkState state_ = TabRendererData::NETWORK_STATE_NONE;
+
+ // 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_;
+
+ ui::Layer waiting_mask_;
+ Arc waiting_arc_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThrobberView);
+};
+
+////////////////////////////////////////////////////////////////////////////////
// Tab, statics:
// static
@@ -1460,7 +1567,7 @@ void Tab::AdvanceLoadingAnimation(TabRendererData::NetworkState state) {
ScheduleIconPaint(); // Repaint the icon area to update favicon visibility.
throbber_->SetVisible(needs_throbber);
}
- throbber_->SchedulePaint();
+ throbber_->SchedulePaintIfRequired();
}
int Tab::IconCapacity() const {
« no previous file with comments | « chrome/browser/ui/views/tabs/tab.h ('k') | ui/gfx/paint_throbber.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698