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

Side by Side Diff: chrome/browser/ui/touch/animation/screen_rotation.cc

Issue 7273073: Animated Rotation (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Move compositing notifications to Layer Created 9 years, 3 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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.
4
5 #include "chrome/browser/ui/touch/animation/screen_rotation.h"
6
7 #include "base/debug/trace_event.h"
8 #include "base/message_loop.h"
9 #include "base/task.h"
10 #include "ui/base/animation/slide_animation.h"
11 #include "ui/gfx/compositor/layer.h"
12 #include "ui/gfx/interpolated_transform.h"
13 #include "ui/gfx/rect.h"
14 #include "ui/gfx/transform.h"
15 #include "views/paint_lock.h"
16 #include "views/view.h"
17
18 namespace {
19 const int kDefaultTransitionDurationMs = 350;
20
21 } // namespace
22
23 ////////////////////////////////////////////////////////////////////////////////
24 // ScreenRotationListener public:
25 //
26
27 ScreenRotationListener::~ScreenRotationListener() {
28 }
29
30 ////////////////////////////////////////////////////////////////////////////////
31 // ScreenRotation public:
32 //
33
34 ScreenRotation::ScreenRotation(views::View* view,
35 ScreenRotationListener* listener,
36 float old_degrees,
37 float new_degrees)
38 : view_(view),
39 listener_(listener),
40 old_degrees_(old_degrees),
41 new_degrees_(new_degrees),
42 last_t_(0.0),
43 duration_(kDefaultTransitionDurationMs),
44 animation_started_(false),
45 animation_stopped_(false) {
46 DCHECK(view);
47 DCHECK(listener);
48
49 if (!view->layer()) {
50 Finalize();
51 } else {
52 // Screen rotations are trigged as a result of a call to SetTransform which
53 // causes a paint to be scheduled to occur. At this point, the paint has
54 // been scheduled, but has not yet been started. We will listen for this
55 // paint to be completed before we start animating.
56 view->layer()->AddObserver(this);
57 }
58 }
59
60 ScreenRotation::~ScreenRotation() {
61 if (view_->layer())
62 view_->layer()->RemoveObserver(this);
63 }
64
65 void ScreenRotation::SetTarget(float degrees) {
66 if (new_degrees_ == degrees)
67 return;
68
69 new_degrees_ = degrees;
70 Init();
71 }
72
73 void ScreenRotation::Stop() {
74 animation_.reset();
75 if (view_->layer()) {
76 if (!interpolated_transform_.get()) {
77 // attempt to initialize.
78 Init();
79 }
80 if (interpolated_transform_.get()) {
81 view_->layer()->SetTransform(interpolated_transform_->Interpolate(1.0));
82 view_->layer()->compositor()->SchedulePaint();
83 }
84 }
85 Finalize();
86 }
87
88 ////////////////////////////////////////////////////////////////////////////////
89 // ScreenRotation private:
90 //
91
92 void ScreenRotation::AnimationProgressed(const ui::Animation* anim) {
93 TRACE_EVENT0("ScreenRotation", "step");
94 last_t_ = static_cast<float>(anim->GetCurrentValue());
95 view_->layer()->SetTransform(interpolated_transform_->Interpolate(last_t_));
96 view_->layer()->compositor()->SchedulePaint();
97 }
98
99 void ScreenRotation::AnimationEnded(const ui::Animation* anim) {
100 TRACE_EVENT_END0("ScreenRotation", "ScreenRotation");
101 // TODO(vollick) massage matrix so that entries sufficiently close
102 // to 0, 1, or -1 are clamped to these values. The idea is to fight
103 // accumulated numeric error due to successive rotations.
104 ui::Transform xform = view_->layer()->transform();
105 gfx::Point origin;
106 xform.TransformPoint(origin);
107 ui::Transform translation;
108 translation.SetTranslate(new_origin_.x() - origin.x(),
109 new_origin_.y() - origin.y());
110 xform.ConcatTransform(translation);
111 view_->layer()->SetTransform(xform);
112 view_->layer()->compositor()->SchedulePaint();
113 animation_stopped_ = true;
114 }
115
116 void ScreenRotation::OnDraw(ui::Layer* layer) {
117 DoPendingWork();
118 }
119
120 void ScreenRotation::Init() {
121 TRACE_EVENT0("ScreenRotation", "init");
122
123 ui::Transform current_transform = view_->layer()->transform();
124 int degrees = new_degrees_ - old_degrees_;
125 degrees = NormalizeAngle(degrees);
126
127 // No rotation required.
128 if (degrees == 0)
129 return;
130
131 gfx::Point old_pivot;
132 gfx::Point new_pivot;
133 int width = view_->layer()->bounds().width();
134 int height = view_->layer()->bounds().height();
135
136 switch (degrees) {
137 case 90:
138 new_origin_ = new_pivot = gfx::Point(width, 0);
139 new_size_.SetSize(height, width);
140 break;
141 case -90:
142 new_origin_ = new_pivot = gfx::Point(0, height);
143 new_size_.SetSize(height, width);
144 break;
145 case 180:
146 duration_ = 550;
147 new_pivot = old_pivot = gfx::Point(width / 2, height / 2);
148 new_origin_.SetPoint(width, height);
149 new_size_.SetSize(width, height);
150 break;
151 }
152
153 // Convert points to world space.
154 current_transform.TransformPoint(old_pivot);
155 current_transform.TransformPoint(new_pivot);
156 current_transform.TransformPoint(new_origin_);
157
158 scoped_ptr<ui::InterpolatedTransform> rotation(
159 new ui::InterpolatedTransformAboutPivot(
160 old_pivot,
161 new ui::InterpolatedRotation(0, degrees)));
162
163 scoped_ptr<ui::InterpolatedTransform> translation(
164 new ui::InterpolatedTranslation(
165 gfx::Point(0, 0),
166 gfx::Point(new_pivot.x() - old_pivot.x(),
167 new_pivot.y() - old_pivot.y())));
168
169 float scale_factor = 0.9f;
170 scoped_ptr<ui::InterpolatedTransform> scale_down(
171 new ui::InterpolatedScale(1.0f, scale_factor, 0.0f, 0.5f));
172
173 scoped_ptr<ui::InterpolatedTransform> scale_up(
174 new ui::InterpolatedScale(1.0f, 1.0f / scale_factor, 0.5f, 1.0f));
175
176 scoped_ptr<ui::InterpolatedTransform> transition(
177 new ui::InterpolatedConstantTransform(current_transform));
178
179 scale_up->SetChild(scale_down.release());
180 translation->SetChild(scale_up.release());
181 rotation->SetChild(translation.release());
182 transition->SetChild(rotation.release());
183
184 if (interpolated_transform_.get()) {
185 // We are in the middle of a transition. In this case, we need to create
186 // an interpolated transform that gets us from where we are to the target
187 // transform.
188 ui::Transform target = transition->Interpolate(1.0);
189 interpolated_transform_.reset(
190 new ui::InterpolatedTRSTransform(
191 current_transform, target, last_t_, 1.0));
192 } else {
193 interpolated_transform_.reset(transition.release());
194 }
195 }
196
197 void ScreenRotation::Start() {
198 TRACE_EVENT_BEGIN0("ScreenRotation", "ScreenRotation");
199 Init();
200 if (interpolated_transform_.get()) {
201 paint_lock_.reset(new views::PaintLock(view_));
202 animation_.reset(new ui::SlideAnimation(this));
203 animation_->SetTweenType(ui::Tween::LINEAR);
204 animation_->SetSlideDuration(duration_);
205 animation_->Show();
206 animation_started_ = true;
207 } else {
208 Finalize();
209 }
210 }
211
212 void ScreenRotation::Finalize() {
213 ui::Transform final_transform = view_->GetTransform();
214 gfx::Rect final_bounds(0, 0, new_size_.width(), new_size_.height());
215 listener_->OnScreenRotationCompleted(final_transform, final_bounds);
216 }
217
218 int ScreenRotation::NormalizeAngle(int degrees) {
219 while (degrees <= -180) degrees += 360;
220 while (degrees > 180) degrees -= 360;
221 return degrees;
222 }
223
224 void ScreenRotation::DoPendingWork() {
225 if (!animation_started_)
226 Start();
227 else if (animation_stopped_) {
228 view_->layer()->RemoveObserver(this);
229 Finalize();
230 }
231 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698