extensions: EventRouter: pass the whole event to WillDispatchCallback
[chromium-blink-merge.git] / ui / gfx / paint_throbber.cc
blob0c4505af6e48352bbe3fd1b880ce0d9a3e9b4e5c
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/gfx/paint_throbber.h"
7 #include "base/time/time.h"
8 #include "third_party/skia/include/core/SkPath.h"
9 #include "ui/gfx/animation/tween.h"
10 #include "ui/gfx/canvas.h"
11 #include "ui/gfx/color_utils.h"
12 #include "ui/gfx/geometry/rect.h"
13 #include "ui/gfx/skia_util.h"
15 namespace gfx {
17 namespace {
19 // The maximum size of the "spinning" state arc, in degrees.
20 const int64_t kMaxArcSize = 270;
22 // The amount of time it takes to grow the "spinning" arc from 0 to 270 degrees.
23 const int64_t kArcTimeMs = 666;
25 // The amount of time it takes for the "spinning" throbber to make a full
26 // rotation.
27 const int64_t kRotationTimeMs = 1568;
29 void PaintArc(Canvas* canvas,
30 const Rect& bounds,
31 SkColor color,
32 SkScalar start_angle,
33 SkScalar sweep) {
34 // Stroke width depends on size.
35 // . For size < 28: 3 - (28 - size) / 16
36 // . For 28 <= size: (8 + size) / 12
37 SkScalar stroke_width = bounds.width() < 28
38 ? 3.0 - SkIntToScalar(28 - bounds.width()) / 16.0
39 : SkIntToScalar(bounds.width() + 8) / 12.0;
40 Rect oval = bounds;
41 // Inset by half the stroke width to make sure the whole arc is inside
42 // the visible rect.
43 int inset = SkScalarCeilToInt(stroke_width / 2.0);
44 oval.Inset(inset, inset);
46 SkPath path;
47 path.arcTo(RectToSkRect(oval), start_angle, sweep, true);
49 SkPaint paint;
50 paint.setColor(color);
51 paint.setStrokeCap(SkPaint::kRound_Cap);
52 paint.setStrokeWidth(stroke_width);
53 paint.setStyle(SkPaint::kStroke_Style);
54 paint.setAntiAlias(true);
55 canvas->DrawPath(path, paint);
58 void CalculateWaitingAngles(const base::TimeDelta& elapsed_time,
59 int64_t* start_angle,
60 int64_t* sweep) {
61 // Calculate start and end points. The angles are counter-clockwise because
62 // the throbber spins counter-clockwise. The finish angle starts at 12 o'clock
63 // (90 degrees) and rotates steadily. The start angle trails 180 degrees
64 // behind, except for the first half revolution, when it stays at 12 o'clock.
65 base::TimeDelta revolution_time = base::TimeDelta::FromMilliseconds(1320);
66 int64_t twelve_oclock = 90;
67 int64_t finish_angle_cc =
68 twelve_oclock + 360 * elapsed_time / revolution_time;
69 int64_t start_angle_cc = std::max(finish_angle_cc - 180, twelve_oclock);
71 // Negate the angles to convert to the clockwise numbers Skia expects.
72 if (start_angle)
73 *start_angle = -finish_angle_cc;
74 if (sweep)
75 *sweep = finish_angle_cc - start_angle_cc;
78 // This is a Skia port of the MD spinner SVG. The |start_angle| rotation
79 // here corresponds to the 'rotate' animation.
80 void PaintThrobberSpinningWithStartAngle(Canvas* canvas,
81 const Rect& bounds,
82 SkColor color,
83 const base::TimeDelta& elapsed_time,
84 int64_t start_angle) {
85 // The sweep angle ranges from -270 to 270 over 1333ms. CSS
86 // animation timing functions apply in between key frames, so we have to
87 // break up the 1333ms into two keyframes (-270 to 0, then 0 to 270).
88 base::TimeDelta arc_time = base::TimeDelta::FromMilliseconds(kArcTimeMs);
89 double arc_size_progress = static_cast<double>(elapsed_time.InMicroseconds() %
90 arc_time.InMicroseconds()) /
91 arc_time.InMicroseconds();
92 // This tween is equivalent to cubic-bezier(0.4, 0.0, 0.2, 1).
93 double sweep = kMaxArcSize * Tween::CalculateValue(Tween::FAST_OUT_SLOW_IN,
94 arc_size_progress);
95 int64_t sweep_keyframe = (elapsed_time / arc_time) % 2;
96 if (sweep_keyframe == 0)
97 sweep -= kMaxArcSize;
99 // This part makes sure the sweep is at least 5 degrees long. Roughly
100 // equivalent to the "magic constants" in SVG's fillunfill animation.
101 const double min_sweep_length = 5.0;
102 if (sweep >= 0.0 && sweep < min_sweep_length) {
103 start_angle -= (min_sweep_length - sweep);
104 sweep = min_sweep_length;
105 } else if (sweep <= 0.0 && sweep > -min_sweep_length) {
106 start_angle += (-min_sweep_length - sweep);
107 sweep = -min_sweep_length;
110 // To keep the sweep smooth, we have an additional rotation after each
111 // |arc_time| period has elapsed. See SVG's 'rot' animation.
112 int64_t rot_keyframe = (elapsed_time / (arc_time * 2)) % 4;
113 PaintArc(canvas, bounds, color, start_angle + rot_keyframe * kMaxArcSize,
114 sweep);
117 } // namespace
119 void PaintThrobberSpinning(Canvas* canvas,
120 const Rect& bounds,
121 SkColor color,
122 const base::TimeDelta& elapsed_time) {
123 base::TimeDelta rotation_time =
124 base::TimeDelta::FromMilliseconds(kRotationTimeMs);
125 int64_t start_angle = 270 + 360 * elapsed_time / rotation_time;
126 PaintThrobberSpinningWithStartAngle(canvas, bounds, color, elapsed_time,
127 start_angle);
130 void PaintThrobberWaiting(Canvas* canvas,
131 const Rect& bounds, SkColor color, const base::TimeDelta& elapsed_time) {
132 int64_t start_angle = 0, sweep = 0;
133 CalculateWaitingAngles(elapsed_time, &start_angle, &sweep);
134 PaintArc(canvas, bounds, color, start_angle, sweep);
137 void PaintThrobberSpinningAfterWaiting(Canvas* canvas,
138 const Rect& bounds,
139 SkColor color,
140 const base::TimeDelta& elapsed_time,
141 ThrobberWaitingState* waiting_state) {
142 int64_t waiting_start_angle = 0, waiting_sweep = 0;
143 CalculateWaitingAngles(waiting_state->elapsed_time, &waiting_start_angle,
144 &waiting_sweep);
146 // |arc_time_offset| is the effective amount of time one would have to wait
147 // for the "spinning" sweep to match |waiting_sweep|. Brute force calculation.
148 if (waiting_state->arc_time_offset == base::TimeDelta()) {
149 for (int64_t arc_time_it = 0; arc_time_it <= kArcTimeMs; ++arc_time_it) {
150 double arc_size_progress = static_cast<double>(arc_time_it) / kArcTimeMs;
151 if (kMaxArcSize * Tween::CalculateValue(Tween::FAST_OUT_SLOW_IN,
152 arc_size_progress) >=
153 waiting_sweep) {
154 // Add kArcTimeMs to sidestep the |sweep_keyframe == 0| offset below.
155 waiting_state->arc_time_offset =
156 base::TimeDelta::FromMilliseconds(arc_time_it + kArcTimeMs);
157 break;
162 // Blend the color between "waiting" and "spinning" states.
163 base::TimeDelta color_fade_time = base::TimeDelta::FromMilliseconds(900);
164 double color_progress = 1.0;
165 if (elapsed_time < color_fade_time) {
166 color_progress = Tween::CalculateValue(
167 Tween::LINEAR_OUT_SLOW_IN,
168 static_cast<double>(elapsed_time.InMicroseconds()) /
169 color_fade_time.InMicroseconds());
171 SkColor blend_color = color_utils::AlphaBlend(color, waiting_state->color,
172 color_progress * 255);
174 int64_t start_angle =
175 waiting_start_angle +
176 360 * elapsed_time / base::TimeDelta::FromMilliseconds(kRotationTimeMs);
177 base::TimeDelta effective_elapsed_time =
178 elapsed_time + waiting_state->arc_time_offset;
180 PaintThrobberSpinningWithStartAngle(canvas, bounds, blend_color,
181 effective_elapsed_time, start_angle);
184 } // namespace gfx